1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-15 06:44:16 +00:00

Use class based view to clean repo code

This commit is contained in:
xiez
2012-09-13 13:31:32 +08:00
parent 0a1457804a
commit 29df42dc64
9 changed files with 240 additions and 208 deletions

22
base/mixins.py Normal file
View File

@@ -0,0 +1,22 @@
from django.utils.decorators import method_decorator
from auth.decorators import login_required
from base.decorators import ctx_switch_required
class LoginRequiredMixin(object):
"""
View mixin which verifies that the user has authenticated.
NOTE:
This should be the left-most mixin of a view.
"""
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(*args, **kwargs)
class CtxSwitchRequiredMixin(object):
@method_decorator(ctx_switch_required)
def dispatch(self, *args, **kwargs):
return super(CtxSwitchRequiredMixin, self).dispatch(*args, **kwargs)

View File

@@ -2,7 +2,8 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from seaserv import ccnet_rpc, ccnet_threaded_rpc, is_valid_filename
from seaserv import ccnet_rpc, ccnet_threaded_rpc, seafserv_threaded_rpc, \
is_valid_filename
from seahub.base.accounts import User
from pysearpc import SearpcError
@@ -178,3 +179,31 @@ class RepoNewDirForm(forms.Form):
except SearpcError, e:
raise forms.ValidationError(str(e))
class RepoPassowrdForm(forms.Form):
"""
Form for user to decrypt a repo in repo page.
"""
repo_id = forms.CharField(error_messages={'required': '参数错误'})
username = forms.CharField(error_messages={'required': '参数错误'})
password = forms.CharField(error_messages={'required': '密码不能为空'})
def clean(self):
if 'password' in self.cleaned_data:
repo_id = self.cleaned_data['repo_id']
username = self.cleaned_data['username']
password = self.cleaned_data['password']
try:
seafserv_threaded_rpc.set_passwd(repo_id, username, password)
except SearpcError, e:
if e.msg == 'Bad arguments':
raise forms.ValidationError(u'url 格式不正确')
# elif e.msg == 'Repo is not encrypted':
# return HttpResponseRedirect(reverse('repo',
# args=[self.repo_id]))
elif e.msg == 'Incorrect password':
raise forms.ValidationError(u'密码不正确,请重新输入')
elif e.msg == 'Internal server error':
raise forms.ValidationError(u'服务器内部故障')
else:
raise forms.ValidationError(u'未知错误')

View File

@@ -1,7 +1,7 @@
from django.conf.urls.defaults import *
from views import *
from seahub.views import repo, repo_history
# from seahub.views import RepoView, RepoHistoryView
urlpatterns = patterns('',
url(r'^create/$', create_org, name='create_org'),
@@ -13,13 +13,14 @@ urlpatterns = patterns('',
url(r'^(?P<url_prefix>[^/]+)/innerpubrepo/unset/(?P<repo_id>[^/]+)/$', unset_org_inner_pub_repo, name='unset_org_inner_pub_repo'),
url(r'^(?P<url_prefix>[^/]+)/groups/$', org_groups, name='org_groups'),
url(r'^([^/]+)/repo/create/$', org_repo_create, name='org_repo_create'),
url(r'^([^/]+)/repo/history/(?P<repo_id>[^/]+)/$', repo_history, name='org_repo_history'),
# url(r'^([^/]+)/repo/history/(?P<repo_id>[^/]+)/$', repo_history, name='org_repo_history'),
# repo share
url(r'^(?P<url_prefix>[^/]+)/shareadmin/$', org_shareadmin, name='org_shareadmin'),
url(r'^(?P<url_prefix>[^/]+)/repo/share/$', org_repo_share, name='org_repo_share'),
url(r'^([^/]+)/repo/(?P<repo_id>[^/]+)/$', repo, name='repo'),
# url(r'^([^/]+)/repo/(?P<repo_id>[^/]+)/$', RepoView.as_view(), name='repo'),
### Org admin ###
url(r'^(?P<url_prefix>[^/]+)/seafadmin/$', org_seafadmin, name='org_seafadmin'),

View File

@@ -49,10 +49,12 @@
<p class="access-notice">该目录已加密。如需在线查看里面的内容请输入解密密码。密码只会在服务器上暂存1小时。</p>
<form action="{{ SITE_ROOT }}repo/{{ repo.id }}/" method="post">
<label>密码:</label>
<input type="hidden" name="repo_id" value="{{ repo.id }}" />
<input type="hidden" name="username" value="{{ request.user.username }}" />
<input id="id_password" type="password" name="password" maxlength="64" /><br />
{% if error %}
<p class="error">{{ error }}</p>
{% endif %}
{% for error in form.errors.values %}
<p class="error">{{ error|escape }}</p>
{% endfor %}
<input type="submit" value="提交" />
</form>

View File

@@ -41,7 +41,7 @@
{% if not forloop.last %}
<td>
<a href="{% url 'seahub.views.repo_history_view' repo.id %}?commit_id={{ commit.id }}" class="op">浏览</a>
<a href="{% url 'repo_history_view' repo.id %}?commit_id={{ commit.id }}" class="op">浏览</a>
<a href="#" data="{{ SITE_ROOT }}repo/history/revert/{{ repo.id }}/?commit_id={{ commit.id }}" class="repo-revert op">还原</a>
</td>
{% else %}

View File

@@ -50,7 +50,7 @@
当前路径:
{% for name, link in zipped %}
{% if not forloop.last %}
<a href="{% url 'seahub.views.repo_history_view' repo.id %}?commit_id={{ current_commit.id }}&p={{ link|urlencode }}">{{ name }}</a> /
<a href="{% url 'repo_history_view' repo.id %}?commit_id={{ current_commit.id }}&p={{ link|urlencode }}">{{ name }}</a> /
{% else %}
{{ name }}
{% endif %}
@@ -67,7 +67,7 @@
{% for dirent in dir_list %}
<tr>
<td class="icon-container"><img src="{{ MEDIA_URL }}img/folder-icon-24.png" alt="目录" /></td>
<td><a href="{% url 'seahub.views.repo_history_view' repo.id %}?commit_id={{ current_commit.id }}&p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{{ dirent.obj_name }}</a></td>
<td><a href="{% url 'repo_history_view' repo.id %}?commit_id={{ current_commit.id }}&p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{{ dirent.obj_name }}</a></td>
<td></td>
<td></td>
</tr>

View File

@@ -26,7 +26,7 @@
{% for name, link in zipped %}
{% if not forloop.last %}
{% if view_history %}
<a href="{% url 'seahub.views.repo_history_view' repo.id %}?commit_id={{ current_commit.id }}&p={{ link|urlencode }}">{{ name }}</a> / {% else %}
<a href="{% url 'repo_history_view' repo.id %}?commit_id={{ current_commit.id }}&p={{ link|urlencode }}">{{ name }}</a> / {% else %}
<a href="{{ SITE_ROOT }}repo/{{ repo.id }}/?p={{ link|urlencode }}">{{ name }}</a> /
{% endif %}
{% else %}

View File

@@ -53,10 +53,10 @@ urlpatterns = patterns('',
(r'^repo/upload_error/(?P<repo_id>[^/]+)/$', upload_file_error),
(r'^repo/update_error/(?P<repo_id>[^/]+)/$', update_file_error),
url(r'^repo/file_revisions/(?P<repo_id>[^/]+)/$', file_revisions, name='file_revisions'),
url(r'^repo/(?P<repo_id>[^/]+)/$', repo, name='repo'),
url(r'^repo/(?P<repo_id>[^/]+)/$', RepoView.as_view(), name='repo'),
(r'^repo/history/(?P<repo_id>[^/]+)/$', repo_history),
(r'^repo/history/revert/(?P<repo_id>[^/]+)/$', repo_history_revert),
(r'^repo/history/view/(?P<repo_id>[^/]+)/$', repo_history_view),
url(r'^repo/history/view/(?P<repo_id>[^/]+)/$', RepoHistoryView.as_view(), name='repo_history_view'),
# (r'^repo/token/modify/(?P<repo_id>[^/]+)/$', modify_token),
(r'^repo/history/changes/(?P<repo_id>[^/]+)/$', repo_history_changes),
(r'^repo/remove/(?P<repo_id>[^/]+)/$', remove_repo),

290
views.py
View File

@@ -22,6 +22,8 @@ from django.shortcuts import render_to_response, redirect
from django.template import Context, loader, RequestContext
from django.utils.hashcompat import md5_constructor
from django.views.decorators.csrf import csrf_protect
from django.views.generic.base import TemplateView, TemplateResponseMixin
from django.views.generic.edit import BaseFormView, FormMixin
from auth.decorators import login_required
from auth.forms import AuthenticationForm, PasswordResetForm, SetPasswordForm, \
@@ -40,6 +42,7 @@ from pysearpc import SearpcError
from base.accounts import User
from base.decorators import sys_staff_required, ctx_switch_required
from base.mixins import LoginRequiredMixin, CtxSwitchRequiredMixin
from seahub.base.models import UuidObjidMap, FileComment
from seahub.contacts.models import Contact
from seahub.contacts.signals import mail_sended
@@ -47,7 +50,8 @@ from group.models import GroupMessage, MessageAttachment
from group.signals import grpmsg_added
from seahub.notifications.models import UserNotification
from forms import AddUserForm, FileLinkShareForm, RepoCreateForm, \
RepoNewDirForm, RepoNewFileForm, FileCommentForm, RepoRenameFileForm
RepoNewDirForm, RepoNewFileForm, FileCommentForm, RepoRenameFileForm, \
RepoPassowrdForm
from utils import render_permission_error, render_error, list_to_string, \
get_httpserver_root, get_ccnetapplet_root, gen_token, \
calculate_repo_last_modify, valid_previewed_file, \
@@ -125,48 +129,55 @@ def gen_path_link(path, repo_name):
return zipped
def render_repo(request, repo_id, error=''):
# Check whether user can view repo page
can_access = access_to_repo(request, repo_id, '')
if not can_access:
return render_permission_error(request, '无法访问该同步目录')
class RepoMixin(object):
def get_repo_id(self):
return self.kwargs.get('repo_id', '')
def get_path(self):
return self.request.GET.get('p', '/')
def get_user(self):
return self.request.user
def get_repo(self, repo_id):
repo = get_repo(repo_id)
if not repo:
return render_error(request, u'该同步目录不存在')
raise Http404
# return render_error(self.request, u'该同步目录不存在')
return repo
# query whether set password if repo is encrypted
def get_repo_size(self):
repo_size = seafserv_threaded_rpc.server_repo_size(self.repo.id)
return repo_size
def is_password_set(self):
password_set = False
if repo.props.encrypted:
if self.repo.encrypted:
try:
ret = seafserv_rpc.is_passwd_set(repo_id, request.user.username)
ret = seafserv_rpc.is_passwd_set(self.repo.id,
self.user.username)
if ret == 1:
password_set = True
except SearpcError, e:
return render_error(request, e.msg)
return password_set
# Get newest commit.
current_commit = get_commits(repo_id, 0, 1)[0]
# query repo infomation
repo_size = seafserv_threaded_rpc.server_repo_size(repo_id)
# get repo dirents
def get_repo_dirents(self):
dirs = []
path = ''
zipped = []
dir_list = []
file_list = []
if not repo.props.encrypted or password_set:
path = request.GET.get('p', '/')
if not self.repo.encrypted or self.password_set:
path = self.path
if path[-1] != '/':
path = path + '/'
if current_commit.root_id == EMPTY_SHA1:
if self.current_commit.root_id == EMPTY_SHA1:
dirs = []
else:
try:
dirs = seafserv_threaded_rpc.list_dir_by_path(current_commit.id,
dirs = seafserv_threaded_rpc.list_dir_by_path(self.current_commit.id,
path.encode('utf-8'))
except SearpcError, e:
return render_error(request, e.msg)
@@ -183,44 +194,119 @@ def render_repo(request, repo_id, error=''):
y.obj_name.lower()))
file_list.sort(lambda x, y : cmp(x.obj_name.lower(),
y.obj_name.lower()))
return (file_list, dir_list)
if request.user.is_authenticated():
def get_nav_path(self):
zipped = gen_path_link(self.path, self.repo.name)
return zipped
def get_applet_root(self):
return get_ccnetapplet_root()
def get_current_commit(self):
# Implemented in subclasses.
pass
def get_success_url(self):
return reverse('repo', args=[self.repo_id])
def get(self, request, *args, **kwargs):
self.repo_id = self.get_repo_id()
self.user = self.get_user()
self.path = self.get_path()
self.repo = self.get_repo(self.repo_id)
self.can_access = True
self.current_commit = self.get_current_commit()
self.password_set = self.is_password_set()
self.repo_size = self.get_repo_size()
self.file_list, self.dir_list = self.get_repo_dirents()
self.zipped = self.get_nav_path()
self.applet_root = self.get_applet_root()
return super(RepoMixin, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.repo_id = self.get_repo_id()
self.user = self.get_user()
self.path = self.get_path()
self.repo = self.get_repo(self.repo_id)
self.can_access = True
self.current_commit = self.get_current_commit()
self.password_set = self.is_password_set()
self.repo_size = self.get_repo_size()
self.file_list, self.dir_list = self.get_repo_dirents()
self.zipped = self.get_nav_path()
self.applet_root = self.get_applet_root()
return super(RepoMixin, self).post(request, *args, **kwargs)
class RepoView(CtxSwitchRequiredMixin, RepoMixin, TemplateResponseMixin,
BaseFormView):
form_class = RepoPassowrdForm
template_name = 'repo.html'
def get_accessible_repos(self):
if self.user.is_authenticated():
try:
accessible_repos = get_accessible_repos(request, repo)
accessible_repos = get_accessible_repos(self.request, self.repo)
except SearpcError, e:
error_msg = e.msg
return render_error(request, error_msg)
return render_error(self.request, error_msg)
else:
accessible_repos = []
return accessible_repos
# generate path and link
zipped = gen_path_link(path, repo.name)
# get groups this repo is shared
if request.user.org:
org_id = request.user.org['org_id']
repo_shared_groups = get_org_groups_by_repo(org_id, repo_id)
def get_repo_shared_groups(self):
if self.user.org:
org_id = self.user.org['org_id']
repo_shared_groups = get_org_groups_by_repo(org_id, self.repo_id)
else:
repo_shared_groups = get_shared_groups_by_repo(repo_id)
repo_shared_groups = get_shared_groups_by_repo(self.repo_id)
# Filter out groups that user is joined.
groups = [ x for x in repo_shared_groups if \
is_group_user(x.id, request.user.username)]
is_group_user(x.id, self.user.username)]
return groups
return render_to_response('repo.html', {
"repo": repo,
"can_access": can_access,
"current_commit": current_commit,
"password_set": password_set,
"repo_size": repo_size,
"dir_list": dir_list,
"file_list": file_list,
"path": path,
"zipped": zipped,
"error": error,
"accessible_repos": accessible_repos,
"applet_root": get_ccnetapplet_root(),
"groups": groups,
}, context_instance=RequestContext(request))
def get_current_commit(self):
current_commit = get_commits(self.repo.id, 0, 1)[0]
return current_commit
def get_context_data(self, **kwargs):
kwargs['repo'] = self.repo
kwargs['can_access'] = self.can_access
kwargs['current_commit'] = self.get_current_commit()
kwargs['password_set'] = self.password_set
kwargs['repo_size'] = self.repo_size
kwargs['dir_list'] = self.dir_list
kwargs['file_list'] = self.file_list
kwargs['path'] = self.path
kwargs['zipped'] = self.zipped
kwargs['accessible_repos'] = self.get_accessible_repos()
kwargs['applet_root'] = self.applet_root
kwargs['groups'] = self.get_repo_shared_groups()
return kwargs
class RepoHistoryView(CtxSwitchRequiredMixin, RepoMixin, TemplateView):
template_name = 'repo_history_view.html'
def get_current_commit(self):
commit_id = self.request.GET.get('commit_id', '')
if not commit_id:
return HttpResponseRedirect(reverse('repo', args=[repo_id]))
current_commit = seafserv_threaded_rpc.get_commit(commit_id)
if not current_commit:
current_commit = get_commits(repo_id, 0, 1)[0]
return current_commit
def get_context_data(self, **kwargs):
kwargs['repo'] = self.repo
kwargs['can_access'] = self.can_access
kwargs['current_commit'] = self.get_current_commit()
kwargs['password_set'] = self.password_set
kwargs['repo_size'] = self.repo_size
kwargs['dir_list'] = self.dir_list
kwargs['file_list'] = self.file_list
kwargs['path'] = self.path
kwargs['zipped'] = self.zipped
return kwargs
@login_required
@ctx_switch_required
@@ -396,31 +482,6 @@ def get_subdir(request):
return HttpResponse(json.dumps(subdirs),
content_type=content_type)
@ctx_switch_required
def repo(request, repo_id):
if request.method == 'GET':
return render_repo(request, repo_id)
elif request.method == 'POST':
password = request.POST.get('password', '')
if not password:
return render_repo(request, repo_id, u'密码不能为空')
try:
seafserv_threaded_rpc.set_passwd(repo_id, request.user.username, password)
except SearpcError, e:
if e.msg == 'Bad arguments':
return render_error(request, u'url 格式不正确')
elif e.msg == 'Repo is not encrypted':
return render_repo(request, repo_id)
elif e.msg == 'Incorrect password':
return render_repo(request, repo_id, u'密码不正确,请重新输入')
elif e.msg == 'Internal server error':
return render_error(request, u'服务器内部故障')
else:
return render_error(request, u'未知错误')
return render_repo(request, repo_id)
@login_required
@ctx_switch_required
def repo_history(request, repo_id):
@@ -515,89 +576,6 @@ def repo_history_revert(request, repo_id):
return HttpResponseRedirect(reverse(repo_history, args=[repo_id]))
@login_required
@ctx_switch_required
def repo_history_view(request, repo_id):
"""
View repo page in history.
"""
# Check whether user can view repo page
can_access = access_to_repo(request, repo_id, '')
if not can_access:
return render_permission_error(request, '无法访问该同步目录')
repo = get_repo(repo_id)
if not repo:
return render_error(request, u'该同步目录不存在')
# query whether set password if repo is encrypted
password_set = False
if repo.props.encrypted:
try:
ret = seafserv_rpc.is_passwd_set(repo_id, request.user.username)
if ret == 1:
password_set = True
except SearpcError, e:
return render_error(request, e.msg)
commit_id = request.GET.get('commit_id', '')
if not commit_id:
return HttpResponseRedirect(reverse('repo', args=[repo_id]))
current_commit = seafserv_threaded_rpc.get_commit(commit_id)
if not current_commit:
current_commit = get_commits(repo_id, 0, 1)[0]
# query repo infomation
repo_size = seafserv_threaded_rpc.server_repo_size(repo_id)
# get repo dirents
dirs = []
path = ''
zipped = []
dir_list = []
file_list = []
if not repo.props.encrypted or password_set:
path = request.GET.get('p', '/')
if path[-1] != '/':
path = path + '/'
if current_commit.root_id == EMPTY_SHA1:
dirs = []
else:
try:
dirs = seafserv_threaded_rpc.list_dir_by_path(current_commit.id,
path.encode('utf-8'))
except SearpcError, e:
return render_error(request, e.msg)
for dirent in dirs:
if stat.S_ISDIR(dirent.props.mode):
dir_list.append(dirent)
else:
file_list.append(dirent)
try:
dirent.file_size = seafserv_threaded_rpc.get_file_size(dirent.obj_id)
except:
dirent.file_size = 0
dir_list.sort(lambda x, y : cmp(x.obj_name.lower(),
y.obj_name.lower()))
file_list.sort(lambda x, y : cmp(x.obj_name.lower(),
y.obj_name.lower()))
# generate path and link
zipped = gen_path_link(path, repo.name)
return render_to_response('repo_history_view.html', {
"repo": repo,
"can_access": can_access,
"current_commit": current_commit,
"password_set": password_set,
"repo_size": repo_size,
"dir_list": dir_list,
"file_list": file_list,
"path": path,
"zipped": zipped,
}, context_instance=RequestContext(request))
def get_diff(repo_id, arg1, arg2):
lists = {'new' : [], 'removed' : [], 'renamed' : [], 'modified' : [], \
'newdir' : [], 'deldir' : []}