1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-13 13:50:07 +00:00

Add org repo create and clean code.

This commit is contained in:
xiez
2012-07-30 10:25:46 +08:00
parent 932dc76bde
commit 061365f434
15 changed files with 190 additions and 319 deletions

View File

@@ -1,8 +1,9 @@
# encoding: utf-8
from django import forms
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from seaserv import ccnet_rpc, ccnet_threaded_rpc
from seaserv import ccnet_rpc, ccnet_threaded_rpc, is_valid_filename
class AddUserForm(forms.Form):
"""
@@ -41,4 +42,55 @@ class FileLinkShareForm(forms.Form):
email = forms.CharField(max_length=512)
file_shared_link = forms.CharField(max_length=40)
class RepoCreateForm(forms.Form):
"""
Form for creating repo and org repo.
"""
repo_name = forms.CharField(max_length=15, error_messages={
'required': '目录名不能为空',
'max_length': '目录名太长不超过50个字符'
})
repo_desc = forms.CharField(max_length=100, error_messages={
'required': '描述不能为空',
'max_length': '描述太长不超过100个字符'
})
encryption = forms.CharField(max_length=1)
passwd = forms.CharField(min_length=3, max_length=15, required=False,
error_messages={
'min_length': '密码太短',
'max_length': '密码太长',
})
passwd_again = forms.CharField(min_length=3, max_length=15, required=False,
error_messages={
'min_length': '密码太短',
'max_length': '密码太长',
})
def clean_repo_name(self):
repo_name = self.cleaned_data['repo_name']
if not is_valid_filename(repo_name):
error_msg = u"您输入的目录名 %s 包含非法字符" % repo_name
raise forms.ValidationError(error_msg)
else:
return repo_name
def clean(self):
"""
Verifiy that the values entered into the two password fields
match.
"""
if 'passwd' in self.cleaned_data and 'passwd_again' in self.cleaned_data:
encryption = self.cleaned_data['encryption']
if int(encryption) == 0:
# This prevents the case that form has passwords but the
# encryption checkbox is not selected.
self.cleaned_data['passwd'] = None
self.cleaned_data['passwd_again'] = None
return self.cleaned_data
else:
passwd = self.cleaned_data['passwd']
passwd_again = self.cleaned_data['passwd_again']
if passwd != passwd_again:
raise forms.ValidationError("两次输入的密码不一致")
return self.cleaned_data

View File

@@ -5,7 +5,7 @@
<form action="" method="post">
<label for="id_org_name">团体名称:</label>
{{ form.org_name}}
<lable for="id_url_prefix">域名前缀</label>
<lable for="id_url_prefix">个性域名:</label>
{{ form.url_prefix }}
<p class="error hide"></p>
{{ form.url_prefix.errors }}

View File

@@ -9,9 +9,9 @@ urlpatterns = patterns('',
url(r'^messages/$', org_msg, name='org_msg'),
url(r'^(?P<url_prefix>[^/]+)/$', org_info, name='org_info'),
url(r'^(?P<url_prefix>[^/]+)/groups/$', org_groups, name='org_groups'),
url(r'^([^/]+)/repo/(?P<repo_id>[^/]+)/$', repo, name='repo'),
url(r'^([^/]+)/repo/history/(?P<repo_id>[^/]+)/$', repo_history, name='org_repo_history'),
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/(?P<repo_id>[^/]+)/$', repo, name='repo'),
### Org admin ###
url(r'^([^/]+)/seafadmin/$', org_seafadmin, name='org_seafadmin'),

View File

@@ -2,18 +2,32 @@ import sys
from django.core.cache import cache
from settings import ORG_CACHE_PREFIX
from seaserv import get_org_id_by_repo_id
def clear_org_ctx(request):
"""
Clear current context.
"""
cache.delete(ORG_CACHE_PREFIX + request.user.username)
request.user.org = None
def set_org_ctx(request, org_dict):
"""
Set current context to org.
"""
cache.set(ORG_CACHE_PREFIX + request.user.username, org_dict, sys.maxint)
request.user.org = org_dict
def access_org_repo(request, repo_id):
"""
Check whether user can view org repo.
Arguments:
- `request`: request must has org dict.
- `repo_id`: repo id
"""
cur_org_id = request.user.org['org_id']
org_id = get_org_id_by_repo_id(repo_id)
return True if cur_org_id == org_id else False

View File

@@ -1,10 +1,12 @@
# encoding: utf-8
import simplejson as json
import sys
from django.core.urlresolvers import reverse
from django.contrib import messages
from django.core.mail import send_mail
from django.contrib.sites.models import Site, RequestSite
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.http import HttpResponse, HttpResponseBadRequest, Http404, \
HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import Context, loader, RequestContext
@@ -12,7 +14,8 @@ from auth.decorators import login_required
from pysearpc import SearpcError
from seaserv import ccnet_threaded_rpc, get_orgs_by_user, get_org_repos, \
get_org_by_url_prefix, create_org, get_user_current_org, add_org_user, \
get_ccnetuser, remove_org_user, get_org_groups, is_valid_filename
get_ccnetuser, remove_org_user, get_org_groups, is_valid_filename, \
create_org_repo
from forms import OrgCreateForm
from signals import org_user_added
@@ -20,6 +23,7 @@ from settings import ORG_CACHE_PREFIX
from utils import set_org_ctx
from notifications.models import UserNotification
from registration.models import RegistrationProfile
from seahub.forms import RepoCreateForm
import seahub.settings as seahub_settings
from seahub.utils import go_error, go_permission_error, validate_group_name, \
emails2list, gen_token
@@ -230,58 +234,34 @@ def org_msg(request):
}, context_instance=RequestContext(request))
@login_required
def org_repo_create(request):
def org_repo_create(request, url_prefix):
'''
Handle ajax post to create org repo.
'''
if request.method != 'POST':
if not request.is_ajax() or request.method != 'POST':
return Http404
repo_name = request.POST.get("repo_name")
repo_desc = request.POST.get("repo_desc")
encrypted = int(request.POST.get("encryption"))
passwd = request.POST.get("passwd")
passwd_again = request.POST.get("passwd_again")
result = {}
content_type = 'application/json; charset=utf-8'
error_msg = ""
if not repo_name:
error_msg = u"目录名不能为空"
elif len(repo_name) > 50:
error_msg = u"目录名太长"
elif not is_valid_filename(repo_name):
error_msg = (u"您输入的目录名 %s 包含非法字符" % repo_name)
elif not repo_desc:
error_msg = u"描述不能为空"
elif len(repo_desc) > 100:
error_msg = u"描述太长"
elif encrypted == 1:
if not passwd:
error_msg = u"密码不能为空"
elif not passwd_again:
error_msg = u"确认密码不能为空"
elif len(passwd) < 3:
error_msg = u"密码太短"
elif len(passwd) > 15:
error_msg = u"密码太长"
elif passwd != passwd_again:
error_msg = u"两次输入的密码不相同"
form = RepoCreateForm(request.POST)
if form.is_valid():
repo_name = form.cleaned_data['repo_name']
repo_desc = form.cleaned_data['repo_desc']
encrypted = form.cleaned_data['encryption']
passwd = form.cleaned_data['passwd']
passwd_again = form.cleaned_data['passwd_again']
if error_msg:
result['error'] = error_msg
return HttpResponse(json.dumps(result), content_type=content_type)
try:
user = request.user.username
org_id = request.user.org['org_id']
repo_id = create_org_repo(repo_name, repo_desc, user, passwd, org_id)
result['success'] = True
except:
result['error'] = u"创建目录失败"
else:
if not repo_id:
result['error'] = u"创建目录失败"
else:
result['success'] = True
return HttpResponse(json.dumps(result), content_type=content_type)
else:
return HttpResponseBadRequest(json.dumps(form.errors),
content_type=content_type)

View File

@@ -1,4 +1,4 @@
{% extends "myhome_base.html" %}
{% extends base_template %}
{% load seahub_tags %}
{% block info_bar_message %}

View File

@@ -1,129 +0,0 @@
$(function() {
//repo-share-form share-list autocomplete
var share_list = [];
{% for contact in contacts %}
share_list.push('{{ contact.contact_email }}');
{% endfor %}
{% for group in groups %}
share_list.push('{{ group.props.group_name }} <{{ group.props.creator_name }}>');
{% endfor %}
$(".repo-share-btn").click(function() {
$("#repo_id").val($(this).attr("data"));
$("#repo-share-form").modal({appendTo: "#main"});
addAutocomplete('#email_or_group', '#repo-share-form', share_list);
});
//check before post
$('#share-submit-btn').click(function() {
if (!$.trim($('#email_or_group').attr('value'))) {
$('#repo-share-form .error').removeClass('hide');
$('#simplemodal-container').css('height', $('#repo-share-form').height());
return false;
}
});
addConfirmTo($('.repo-delete-btn'));
addConfirmTo($('.unshare-btn'), '确定要取消共享?');
$(".download-btn").click(function() {
window.open('{{ SITE_ROOT }}seafile_access_check/?repo_id=' + $(this).attr('data'));
});
//show op images when mouse hover on
$("table tr:gt(0)").hover(
function() {
$(this).find('img').css('cursor', 'pointer').removeClass('vh');
},
function() {
$(this).find('img').addClass('vh');
}
);
});
//repo-create-form
$('#repo-create').hover(
function() {
$(this).css({'background-color': '#fff', 'cursor': 'pointer'});
},
function() {
$(this).css('background-color', '#f5f5f5');
}
);
$('#repo-create').click(function() {
$('#repo-create-form').modal({appendTo: '#main', autoResize: true});
});
$('#encrypt-switch').click(function () {
if ($(this).attr('checked')) {
$('#repo-create-form input[type="password"]').attr('disabled', false).removeClass('input-disabled');
} else {
$('#repo-create-form input[type="password"]').attr('disabled', true).addClass('input-disabled');
}
});
function showError(err) {
$('#repo-create-form .error').html(err).attr('class','error');
$('#simplemodal-container').css('height', $('#repo-create-form').height());
}
$('#repo-create-submit').click(function() {
var passwd = $('#repo-create-form input[name="passwd"]'),
passwd_again = $('#repo-create-form input[name="passwd_again"]');
if (!$('#repo-name').val()) {
showError('目录名不能为空。');
return false;
}
if (!$('#repo-desc').val()) {
showError('描述不能为空。');
return false;
}
if ($('#encrypt-switch').attr('checked')) {
if (!passwd.val()) {
showError('密码不能为空。');
return false;
}
if (!passwd_again.val()) {
showError('请确认密码。');
return false;
}
if (passwd.val().length < 3) {
showError('密码太短');
return false;
}
if (passwd.val().length > 15) {
showError('密码太长。');
return false;
}
if (passwd.val() != passwd_again.val()) {
showError('两次输入的密码不一致。');
return false;
}
}
$.ajax({
url: '{{ url }}',
type: 'POST',
dataType: 'json',
cache: 'false',
contentType: 'application/json; charset=utf-8',
beforeSend: prepareCSRFToken,
data: {
'repo_name': $('#repo-name').val(),
'repo_desc': $('#repo-desc').val(),
'encryption': $('#encrypt-switch').attr('checked') ? 1 : 0,
'passwd': passwd.val(),
'passwd_again': passwd_again.val()
},
success: function(data) {
if (data['success']) {
location.reload(true);
} else {
showError(data['error']);
}
}
});
return false;
});

View File

@@ -1,4 +1,4 @@
{% extends "myhome_base.html" %}
{% extends base_template %}
{% load seahub_tags %}
{% block left_panel %}

View File

@@ -1,4 +1,4 @@
{% extends "myhome_base.html" %}
{% extends base_template %}
{% load seahub_tags %}
{% block info_bar_message %}

View File

@@ -1,4 +1,4 @@
{% extends "myhome_base.html" %}
{% extends base_template %}
{% load seahub_tags %}
{% block info_bar_message %}

View File

@@ -69,7 +69,7 @@ function showError(err) {
$('#repo-create-submit').click(function() {
var passwd = $('#repo-create-form input[name="passwd"]'),
passwd_again = $('#repo-create-form input[name="passwd_again"]');
/*
if (!$('#repo-name').val()) {
showError('目录名不能为空。');
return false;
@@ -78,7 +78,6 @@ $('#repo-create-submit').click(function() {
showError('描述不能为空。');
return false;
}
if ($('#encrypt-switch').attr('checked')) {
if (!passwd.val()) {
showError('密码不能为空。');
@@ -101,13 +100,12 @@ $('#repo-create-submit').click(function() {
return false;
}
}
*/
$.ajax({
url: '{{ url }}',
type: 'POST',
dataType: 'json',
cache: 'false',
contentType: 'application/json; charset=utf-8',
beforeSend: prepareCSRFToken,
data: {
'repo_name': $('#repo-name').val(),
@@ -117,12 +115,17 @@ $('#repo-create-submit').click(function() {
'passwd_again': passwd_again.val()
},
success: function(data) {
alert(data);
if (data['success']) {
location.reload(true);
} else {
showError(data['error']);
}
},
error: function(data, textStatus, jqXHR) {
var errors = $.parseJSON(data.responseText);
$.each(errors, function(index, value) {
showError(value[0]);
});
}
});

View File

@@ -3,14 +3,15 @@ import service
from service import ccnet_rpc, monitor_rpc, seafserv_rpc, \
seafserv_threaded_rpc, ccnet_threaded_rpc
from service import send_command
from service import get_org_groups, get_personal_groups
from service import get_repos, get_repo, get_commits, get_branches, get_org_repos
from service import get_binding_peerids
from service import get_ccnetuser, get_emailusers
from service import get_group_repoids, check_group_staff
from service import get_org_groups, get_personal_groups, get_group_repoids, \
check_group_staff
from service import get_repos, get_repo, get_commits, get_branches, \
get_org_repos, is_repo_owner, create_org_repo
from service import get_binding_peerids, is_valid_filename
from service import create_org, get_orgs_by_user, get_org_by_url_prefix, \
get_user_current_org, add_org_user, remove_org_user, get_org_by_id, \
is_valid_filename
get_org_id_by_repo_id
from service import CCNET_CONF_PATH

View File

@@ -220,6 +220,7 @@ def create_org_repo(repo_name, repo_desc, user, passwd, org_id):
def get_org_repos(org_id, start, limit):
"""
List repos created in org.
"""
try:
repos = seafserv_threaded_rpc.get_org_repo_list(org_id, start, limit)
@@ -228,9 +229,29 @@ def get_org_repos(org_id, start, limit):
return repos
def get_org_id_by_repo_id(repo_id):
"""
Get org id according repo id.
"""
try:
org_id = seafserv_threaded_rpc.get_org_id_by_repo_id(repo_id)
except SearpcError:
org_id = ''
return org_id
def get_repo(repo_id):
return seafserv_threaded_rpc.get_repo(repo_id)
def is_repo_owner(user, repo_id):
"""
Check whether user is repo owner.
"""
try:
ret = seafserv_threaded_rpc.is_repo_owner(user, repo_id)
except SearpcError:
ret = 0
return ret
def get_commits(repo_id, offset, limit):
"""Get commit lists."""
return seafserv_threaded_rpc.get_commit_list(repo_id, offset, limit)

161
views.py
View File

@@ -14,7 +14,8 @@ from django.contrib import messages
from django.contrib.sites.models import Site, RequestSite
from django.db import IntegrityError
from django.db.models import F
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.http import HttpResponse, HttpResponseBadRequest, Http404, \
HttpResponseRedirect
from django.shortcuts import render_to_response, redirect
from django.template import Context, loader, RequestContext
from django.views.decorators.csrf import csrf_protect
@@ -30,15 +31,15 @@ from share.models import FileShare
from seaserv import ccnet_rpc, ccnet_threaded_rpc, get_repos, get_emailusers, \
get_repo, get_commits, get_branches, is_valid_filename, \
seafserv_threaded_rpc, seafserv_rpc, get_binding_peerids, get_ccnetuser, \
get_group_repoids, check_group_staff, get_personal_groups
get_group_repoids, check_group_staff, get_personal_groups, is_repo_owner
from pysearpc import SearpcError
from seahub.base.accounts import CcnetUser
from seahub.base.models import UuidOjbidMap
from seahub.contacts.models import Contact
from seahub.notifications.models import UserNotification
from seahub.organizations.utils import clear_org_ctx
from forms import AddUserForm, FileLinkShareForm
from seahub.organizations.utils import clear_org_ctx, access_org_repo
from forms import AddUserForm, FileLinkShareForm, RepoCreateForm
from utils import go_permission_error, go_error, list_to_string, \
get_httpserver_root, get_ccnetapplet_root, gen_token, \
calculate_repo_last_modify, valid_previewed_file, \
@@ -52,26 +53,18 @@ from seahub.settings import FILE_PREVIEW_MAX_SIZE, CROCODOC_API_TOKEN
def root(request):
return HttpResponseRedirect(reverse(myhome))
def validate_owner(request, repo_id):
"""
Check whether email in the request own the repo
Check whether user in the request owns the repo.
"""
try:
ret = seafserv_threaded_rpc.is_repo_owner(request.user.username,
repo_id)
except:
ret = 0
ret = is_repo_owner(request.user.username, repo_id)
if ret == 0 or ret is None:
return False
else:
return True
return True if ret else False
def validate_emailuser(emailuser):
"""
check whether emailuser is in the database
Check whether user is registerd.
"""
try:
@@ -120,13 +113,14 @@ def access_to_repo(request, repo_id, repo_ap):
Check whether user in the request can access to repo, which means user can
view directory entries on repo page. Only repo owner or person who is shared
can access to repo.
NOTE: `repo_ap` may be used in future.
"""
if repo_ap == 'own' and not validate_owner(request, repo_id) \
and not check_shared_repo(request, repo_id):
return False
else:
if validate_owner(request, repo_id) or check_shared_repo(request, repo_id)\
or access_org_repo(request, repo_id):
return True
else:
return False
def gen_path_link(path, repo_name):
"""
@@ -153,18 +147,8 @@ def gen_path_link(path, repo_name):
return zipped
def render_repo(request, repo_id, error=''):
# get repo web access property, if no repo access property in db, then
# assume repo ap is 'own'
# repo_ap = seafserv_threaded_rpc.repo_query_access_property(repo_id)
# if not repo_ap:
# repo_ap = 'own'
# Since repo web access property is removed since 0.9.4, we assume all repo
# is 'own' for compatibility
repo_ap = 'own'
# Check whether user can view repo page
can_access = access_to_repo(request, repo_id, repo_ap)
can_access = access_to_repo(request, repo_id, '')
if not can_access:
return go_permission_error(request, '无法访问该同步目录')
@@ -250,7 +234,6 @@ def render_repo(request, repo_id, error=''):
"view_history": view_history,
"is_owner": is_owner,
"password_set": password_set,
"repo_ap": repo_ap,
"repo_size": repo_size,
"dir_list": dir_list,
"file_list": file_list,
@@ -482,11 +465,7 @@ def repo_history(request, repo_id):
"""
View repo history
"""
repo_ap = seafserv_threaded_rpc.repo_query_access_property(repo_id)
if not repo_ap:
repo_ap = 'own'
if not access_to_repo(request, repo_id, repo_ap):
if not access_to_repo(request, repo_id, ''):
return go_permission_error(request, u'无法浏览该同步目录修改历史')
repo = get_repo(repo_id)
@@ -607,11 +586,7 @@ def repo_history_changes(request, repo_id):
changes = {}
content_type = 'application/json; charset=utf-8'
repo_ap = seafserv_threaded_rpc.repo_query_access_property(repo_id)
if repo_ap == None:
repo_ap = 'own'
if not access_to_repo(request, repo_id, repo_ap):
if not access_to_repo(request, repo_id, ''):
return HttpResponse(json.dumps(changes),
content_type=content_type)
@@ -657,8 +632,10 @@ def modify_token(request, repo_id):
@login_required
def remove_repo(request, repo_id):
if not validate_owner(request, repo_id) and not request.user.is_staff:
return go_permission_error(request, u'删除同步目录失败')
if not validate_owner(request, repo_id) and not request.user.is_staff \
and not request.user.org['is_staff']:
err_msg = u'删除同步目录失败, 只有管理员或目录创建者有权删除目录。'
return go_permission_error(request, err_msg)
seafserv_threaded_rpc.remove_repo(repo_id)
next = request.GET.get('next', '/')
@@ -816,24 +793,14 @@ def repo_view_file(request, repo_id):
if not repo:
raise Http404
# if a repo is shared to me, then I can view and download file no mater whether
# repo's access property is 'own' or 'public'
if check_shared_repo(request, repo_id):
share_to_me = True
else:
share_to_me = False
token = ''
# people who is owner or this repo is shared to him, can visit the repo;
# others, just go to 404 page
if validate_owner(request, repo_id) or share_to_me:
# owner should get a token to visit repo
if access_to_repo(request, repo_id, ''):
# Get a token to visit file
token = gen_token()
# put token into memory in seaf-server
seafserv_rpc.web_save_access_token(token, repo_id, obj_id,
'view', request.user.username)
else:
raise Http404
go_permission_error(request, '无法查看该文件')
# generate path and link
zipped = gen_path_link(path, repo.name)
@@ -974,19 +941,6 @@ def repo_access_file(request, repo_id, obj_id):
if op == 'del':
return repo_del_file(request, repo_id)
# if a repo doesn't have access property in db, then assume it's 'own'
# repo_ap = seafserv_threaded_rpc.repo_query_access_property(repo_id)
# if not repo_ap:
# repo_ap = 'own'
repo_ap = 'own'
# if a repo is shared to me, then I can view and download file no mater whether
# repo's access property is 'own' or 'public'
if check_shared_repo(request, repo_id):
share_to_me = True
else:
share_to_me = False
# If vistor's file shared token in url params matches the token in db,
# then we know the vistor is from file shared link.
share_token = request.GET.get('t', '')
@@ -997,17 +951,13 @@ def repo_access_file(request, repo_id, obj_id):
from_shared_link = False
token = ''
if repo_ap == 'own':
# people who is owner or this repo is shared to him, can visit the repo;
# others, just go to 404 page
if validate_owner(request, repo_id) or share_to_me or from_shared_link:
# owner should get a token to visit repo
if access_to_repo(request, repo_id, '') or from_shared_link:
# Get a token to access file
token = gen_token()
# put token into memory in seaf-server
seafserv_rpc.web_save_access_token(token, repo_id, obj_id,
op, request.user.username)
else:
raise Http404
go_permission_error(request, '无法访问文件')
redirect_url = gen_file_get_url(token, file_name)
return HttpResponseRedirect(redirect_url)
@@ -1667,55 +1617,34 @@ def repo_create(request):
Handle ajax post.
'''
if request.method == 'POST':
repo_name = request.POST.get("repo_name")
repo_desc = request.POST.get("repo_desc")
encrypted = int(request.POST.get("encryption"))
passwd = request.POST.get("passwd")
passwd_again = request.POST.get("passwd_again")
if not request.is_ajax() or request.method != 'POST':
return Http404
result = {}
content_type = 'application/json; charset=utf-8'
error_msg = ""
if not repo_name:
error_msg = u"目录名不能为空"
elif len(repo_name) > 50:
error_msg = u"目录名太长"
elif not is_valid_filename(repo_name):
error_msg = (u"您输入的目录名 %s 包含非法字符" % repo_name)
elif not repo_desc:
error_msg = u"描述不能为空"
elif len(repo_desc) > 100:
error_msg = u"描述太长"
elif encrypted == 1:
if not passwd:
error_msg = u"密码不能为空"
elif not passwd_again:
error_msg = u"确认密码不能为空"
elif len(passwd) < 3:
error_msg = u"密码太短"
elif len(passwd) > 15:
error_msg = u"密码太长"
elif passwd != passwd_again:
error_msg = u"两次输入的密码不相同"
if error_msg:
result['error'] = error_msg
return HttpResponse(json.dumps(result), content_type=content_type)
form = RepoCreateForm(request.POST)
if form.is_valid():
repo_name = form.cleaned_data['repo_name']
repo_desc = form.cleaned_data['repo_desc']
encrypted = form.cleaned_data['encryption']
passwd = form.cleaned_data['passwd']
passwd_again = form.cleaned_data['passwd_again']
user = request.user.username
try:
repo_id = seafserv_threaded_rpc.create_repo(repo_name, repo_desc, request.user.username, passwd)
result['success'] = True
repo_id = seafserv_threaded_rpc.create_repo(repo_name, repo_desc,
user, passwd)
except:
result['error'] = u"创建目录失败"
else:
repo_id = None
if not repo_id:
result['error'] = u"创建目录失败"
else:
result['success'] = True
return HttpResponse(json.dumps(result), content_type=content_type)
else:
return HttpResponseBadRequest(json.dumps(form.errors),
content_type=content_type)
def render_file_revisions (request, repo_id):
"""List all history versions of a file."""