1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-30 13:23:14 +00:00

Merge branch 'sub-repo'

This commit is contained in:
zhengxie 2013-06-21 15:41:47 +08:00
commit aa4e334a12
7 changed files with 177 additions and 15 deletions

View File

@ -213,5 +213,5 @@ class RepoSettingForm(forms.Form):
repo_id = forms.CharField(error_messages={'required': _('Repo id is required')}) repo_id = forms.CharField(error_messages={'required': _('Repo id is required')})
repo_name = forms.CharField(error_messages={'required': _('Library name is required')}) repo_name = forms.CharField(error_messages={'required': _('Library name is required')})
repo_desc = forms.CharField(error_messages={'required': _('Library description is required')}) repo_desc = forms.CharField(error_messages={'required': _('Library description is required')})
days = forms.IntegerField(error_messages={'required': _('Days can\'t be empty'), days = forms.IntegerField(required=False,
'invalid': _('Please enter a number')}) error_messages={'invalid': _('Please enter a number')})

View File

@ -346,6 +346,8 @@ SEND_EMAIL_ON_RESETTING_USER_PASSWD = True # Whether to send email when a system
ENABLE_PUBFILE = False ENABLE_PUBFILE = False
ENABLE_SUB_LIBRARY = False
##################### #####################
# External settings # # External settings #
##################### #####################

View File

@ -116,9 +116,12 @@
<div class="repo-file-op vh"> <div class="repo-file-op vh">
<div class="displayed-op"> <div class="displayed-op">
<a class="op" href="{% url 'repo_download_dir' repo.id %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{% trans 'Download' %}</a> <a class="op" href="{% url 'repo_download_dir' repo.id %}?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{% trans 'Download' %}</a>
{% if not repo.encrypted %} {% if not repo.encrypted %}
<a class="op file-share" href="#" data-name="{{ dirent.obj_name }}" data-link="{{ dirent.sharelink }}" data-token="{{ dirent.sharetoken }}" data-type="d">{% trans "Share" %}</a> <a class="op file-share" href="#" data-name="{{ dirent.obj_name }}" data-link="{{ dirent.sharelink }}" data-token="{{ dirent.sharetoken }}" data-type="d">{% trans "Share" %}</a>
{% endif %} {% endif %}
{% if ENABLE_SUB_LIBRARY and not repo.is_virtual %}
<a class="op create-sub-repo" href="#" data-name="{{ dirent.obj_name }}">{% trans "Sub-library" %}</a>
{% endif %}
</div> </div>
{% if user_perm == 'rw' %} {% if user_perm == 'rw' %}
<img src="{{ MEDIA_URL }}img/dropdown-arrow.png" title="{% trans 'More operations'%}" alt="{% trans 'More operations'%}" class="more-op-icon" data="no-popup" /> <img src="{{ MEDIA_URL }}img/dropdown-arrow.png" title="{% trans 'More operations'%}" alt="{% trans 'More operations'%}" class="more-op-icon" data="no-popup" />
@ -239,12 +242,14 @@
<input type="text" name="repo_name" value="{{ repo.name }}" class="long-input" /><br /> <input type="text" name="repo_name" value="{{ repo.name }}" class="long-input" /><br />
<label>{% trans "Description" %}</label></br /> <label>{% trans "Description" %}</label></br />
<input type="text" name="repo_desc" value="{{ repo.desc }}" class="long-input" /><br /> <input type="text" name="repo_desc" value="{{ repo.desc }}" class="long-input" /><br />
<label>{% trans "History" %}</label><br />
<input type="hidden" name="repo_id" value="{{ repo.id }}" /> <input type="hidden" name="repo_id" value="{{ repo.id }}" />
{% if not ENABLE_SUB_LIBRARY or not repo.is_virtual %}
<label>{% trans "History" %}</label><br />
<input type="radio" name="history" value="full_history" {% if history_limit < 0 %}checked="checked"{% endif %} /> {% trans "Keep full history" %}<br /> <input type="radio" name="history" value="full_history" {% if history_limit < 0 %}checked="checked"{% endif %} /> {% trans "Keep full history" %}<br />
<input type="radio" name="history" value="no_history" {% if history_limit == 0 %}checked="checked"{% endif %} /> {% trans "Don't keep history" %}<br /> <input type="radio" name="history" value="no_history" {% if history_limit == 0 %}checked="checked"{% endif %} /> {% trans "Don't keep history" %}<br />
<input type="radio" name="history" value="partial_history" {% if history_limit > 0 %}checked="checked"{% endif %} /> {% trans "Only keep a period of history:" %} <input type="radio" name="history" value="partial_history" {% if history_limit > 0 %}checked="checked"{% endif %} /> {% trans "Only keep a period of history:" %}
<input type="text" name="days" size="4" {% if history_limit <= 0 %} disabled="disabled" class="input-disabled" {% else %} value="{{history_limit}}" {% endif %} /> {% trans "days" %}<br /> <input type="text" name="days" size="4" {% if history_limit <= 0 %} disabled="disabled" class="input-disabled" {% else %} value="{{history_limit}}" {% endif %} /> {% trans "days" %}<br />
{% endif %}
<p class="error hide"></p> <p class="error hide"></p>
<input type="submit" value="{% trans "Submit" %}" class="submit" /> <input type="submit" value="{% trans "Submit" %}" class="submit" />
<button class="simplemodal-close">{% trans "Cancel" %}</button> <button class="simplemodal-close">{% trans "Cancel" %}</button>
@ -358,6 +363,7 @@ $('#repo-setting-btn').click(function () {
$('#repo-setting-form').modal({appendTo:'#main'}); $('#repo-setting-form').modal({appendTo:'#main'});
}); });
{% if not ENABLE_SUB_LIBRARY or not repo.is_virtual %}
$('#repo-setting-form input[name="history"]').change(function() { $('#repo-setting-form input[name="history"]').change(function() {
var value = $(this).attr('value'); var value = $(this).attr('value');
if (value == 'full_history' || value == 'no_history') { if (value == 'full_history' || value == 'no_history') {
@ -366,8 +372,10 @@ $('#repo-setting-form input[name="history"]').change(function() {
$('#repo-setting-form input[name="days"]').attr('disabled', false).removeClass('input-disabled'); $('#repo-setting-form input[name="days"]').attr('disabled', false).removeClass('input-disabled');
} }
}); });
{% endif %}
$('#repo-setting-form').submit(function() { $('#repo-setting-form').submit(function() {
{% if not ENABLE_SUB_LIBRARY or not repo.is_virtual %}
var days; var days;
var value = $(this).find('input[name="history"]:checked').val(); var value = $(this).find('input[name="history"]:checked').val();
@ -378,6 +386,7 @@ $('#repo-setting-form').submit(function() {
} else { } else {
days = 0; days = 0;
} }
{% endif %}
var submit_btn = $(this).children('input[type="submit"]'); var submit_btn = $(this).children('input[type="submit"]');
disable(submit_btn); disable(submit_btn);
@ -390,7 +399,9 @@ $('#repo-setting-form').submit(function() {
'repo_id': $('#repo-setting-form input[name="repo_id"]').val(), 'repo_id': $('#repo-setting-form input[name="repo_id"]').val(),
'repo_name': $('#repo-setting-form input[name="repo_name"]').val(), 'repo_name': $('#repo-setting-form input[name="repo_name"]').val(),
'repo_desc': $('#repo-setting-form input[name="repo_desc"]').val(), 'repo_desc': $('#repo-setting-form input[name="repo_desc"]').val(),
{% if not ENABLE_SUB_LIBRARY or not repo.is_virtual %}
'days': days 'days': days
{% endif %}
}, },
success: function(data) { success: function(data) {
if (data['success']) { if (data['success']) {
@ -919,6 +930,45 @@ $('#mv-dir-list h5').click(function() {
next.addClass('hide'); next.addClass('hide');
} }
}); });
{% if ENABLE_SUB_LIBRARY and not repo.is_virtual %}
$('.create-sub-repo').click(function() {
var repo_name = $(this).data('name');
var orig_path = '{{path}}' + repo_name;
feedback('{% trans "Creating sub-library..." %}', 'info');
$.ajax({
url: '{{ SITE_ROOT }}repo/create_sub_repo/',
type: 'POST',
cache: false,
beforeSend: prepareCSRFToken,
dataType: 'json',
data: {
orig_repo_id: '{{repo.id}}',
orig_path: orig_path,
repo_name: repo_name,
repo_desc: repo_name
},
success:function(data) {
if (data['success']) {
var sub_repo_id = data['repo_id'];
feedback('{% trans "Created sub-library" %} <a href="{{SITE_ROOT}}repo/' + sub_repo_id + '">' + repo_name + '</a>', 'info');
} else {
feedback(data['error'], 'error');
}
},
error:function(xhr, textStatus, errorThrown) {
if (xhr.responseText) {
feedback(jQuery.parseJSON(xhr.responseText).error, 'error');
} else {
feedback("{% trans "Failed. Please check the network." %}", 'error');
}
}
});
});
{% endif %}
{% if path == '/' %} {% if path == '/' %}
{% include "snippets/list_commit_detail.html" %} {% include "snippets/list_commit_detail.html" %}
{% endif %} {% endif %}

View File

@ -4,6 +4,9 @@
<div class="ovhd"> <div class="ovhd">
<ul class="fleft" id="tabs-nav"> <ul class="fleft" id="tabs-nav">
<li><a href="#my-own-repos">{% trans "Mine" %}</a></li> <li><a href="#my-own-repos">{% trans "Mine" %}</a></li>
{% if ENABLE_SUB_LIBRARY %}
<li><a href="#my-sub-repos">{% trans "Sub-libraries" %}</a></li>
{% endif %}
<li><a href="#repos-shared-to-me">{% trans "Shared" %}</a></li> <li><a href="#repos-shared-to-me">{% trans "Shared" %}</a></li>
<li><a href="#starred-files">{% trans "Starred" %}</a></li> <li><a href="#starred-files">{% trans "Starred" %}</a></li>
</ul> </ul>
@ -20,6 +23,7 @@
<th width="14%">{% trans "Operations" %}</th> <th width="14%">{% trans "Operations" %}</th>
</tr> </tr>
{% for repo in owned_repos %} {% for repo in owned_repos %}
{% if not ENABLE_SUB_LIBRARY or not repo.is_virtual %}
<tr> <tr>
<td><img src="{{MEDIA_URL}}img/sync-folder-20.png" title="{% trans "Read-Write" %}" alt="{% trans "directory icon" %}" /></td> <td><img src="{{MEDIA_URL}}img/sync-folder-20.png" title="{% trans "Read-Write" %}" alt="{% trans "directory icon" %}" /></td>
<td><a href="{{ SITE_ROOT }}repo/{{ repo.props.id }}/">{{ repo.props.name }}</a></td> <td><a href="{{ SITE_ROOT }}repo/{{ repo.props.id }}/">{{ repo.props.name }}</a></td>
@ -35,6 +39,7 @@
<span data-url="{{ SITE_ROOT }}repo/remove/{{ repo.props.id }}/?next={{ request.path }}" data-target="{{ repo.props.name }}" class="icon-trash repo-delete-btn op-icon vh" title="{% trans "Delete" %}"></span> <span data-url="{{ SITE_ROOT }}repo/remove/{{ repo.props.id }}/?next={{ request.path }}" data-target="{{ repo.props.name }}" class="icon-trash repo-delete-btn op-icon vh" title="{% trans "Delete" %}"></span>
</td> </td>
</tr> </tr>
{% endif %}
{% endfor %} {% endfor %}
</table> </table>
{% else %} {% else %}
@ -47,6 +52,53 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% if ENABLE_SUB_LIBRARY %}
<div id="my-sub-repos" class="hide">
{% if sub_repos %}
<table>
<tr>
<th width="4%"><!--icon--></th>
<th width="24%">{% trans "Name" %}</th>
<th width="43%">{% trans "Origin" %}</th>
<th width="15%">{% trans "Last Update" %}</th>
<th width="14%">{% trans "Operations" %}</th>
</tr>
{% for repo in sub_repos %}
<tr>
<td>
{% if repo.virtual_perm == 'rw' %}
<img src="{{MEDIA_URL}}img/sync-folder-20.png" title="{% trans "Read-Write" %}" alt="{% trans "directory icon" %}" />
{% else %}
<img src="{{MEDIA_URL}}img/folder-no-write-20.png" title="{% trans "Read-Only" %}" alt="{% trans "directory icon" %}" />
{% endif %}
</td>
<td><a href="{{ SITE_ROOT }}repo/{{ repo.id }}/">{{ repo.name }}</a></td>
<td><a href="{{ SITE_ROOT }}repo/{{ repo.origin_repo_id}}/?p={{ repo.origin_path }}">{{ repo.abbrev_origin_path }}</a></td>
{% if repo.latest_modify %}
<td>{{ repo.latest_modify|translate_seahub_time }}</td>
{% else %}
<td>--</td>
{% endif %}
<td>
<span data="{{ repo.props.id }}" class="icon-cloud-download download-btn op-icon vh" title="{% trans "Download and Sync" %}"></span>
{% if repo.is_original_owner %}
<span data-id="{{ repo.props.id }}" data-name="{{ repo.props.name }}" class="sf-icon-share repo-share-btn op-icon vh" title="{% trans "Share" %}"></span>
{% endif %}
<span data-url="{{ SITE_ROOT }}repo/remove/{{ repo.props.id }}/?next={{ request.path }}" data-target="{{ repo.props.name }}" class="icon-trash repo-delete-btn op-icon vh" title="{% trans "Delete" %}"></span>
</td>
</tr>
{% endfor %}
</table>
{% else %}
<div class="empty-tips">
<h2 class="center-contents">{% trans "You have not created any sub-libraries" %}</h2>
<p>{% trans "You can create a sub-library from a directory inside a library. A sub-library can be independently synced and shared. Files in the sub-library will be automatically kept in sync with the directory of the origin library." %}</p>
</div>
{% endif %}
</div>
{% endif %}
<div id="repos-shared-to-me" class="hide"> <div id="repos-shared-to-me" class="hide">
{% if in_repos %} {% if in_repos %}
<table> <table>
@ -92,6 +144,7 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div id="starred-files" class="hide"> <div id="starred-files" class="hide">
{% if starred_files %} {% if starred_files %}
<table> <table>

View File

@ -81,6 +81,7 @@ urlpatterns = patterns('',
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/file/edit/$', file_edit, name='file_edit'), url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/file/edit/$', file_edit, name='file_edit'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/(?P<obj_id>[^/]+)/$', repo_access_file, name='repo_access_file'), url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/(?P<obj_id>[^/]+)/$', repo_access_file, name='repo_access_file'),
(r'^repo/save_settings$', repo_save_settings), (r'^repo/save_settings$', repo_save_settings),
url(r'^repo/create_sub_repo/$', create_sub_repo, name='create_sub_repo'),
url(r'^f/(?P<token>[a-f0-9]{10})/$', view_shared_file, name='view_shared_file'), url(r'^f/(?P<token>[a-f0-9]{10})/$', view_shared_file, name='view_shared_file'),
url(r'^d/(?P<token>[a-f0-9]{10})/$', view_shared_dir, name='view_shared_dir'), url(r'^d/(?P<token>[a-f0-9]{10})/$', view_shared_dir, name='view_shared_dir'),

View File

@ -85,7 +85,8 @@ if HAS_OFFICE_CONVERTER:
import seahub.settings as settings import seahub.settings as settings
from seahub.settings import FILE_PREVIEW_MAX_SIZE, INIT_PASSWD, USE_PDFJS, FILE_ENCODING_LIST, \ from seahub.settings import FILE_PREVIEW_MAX_SIZE, INIT_PASSWD, USE_PDFJS, FILE_ENCODING_LIST, \
FILE_ENCODING_TRY_LIST, SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER, SEND_EMAIL_ON_RESETTING_USER_PASSWD FILE_ENCODING_TRY_LIST, SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER, SEND_EMAIL_ON_RESETTING_USER_PASSWD, \
ENABLE_SUB_LIBRARY
# Get an instance of a logger # Get an instance of a logger
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -347,14 +348,15 @@ def repo_save_settings(request):
status=500, content_type=content_type) status=500, content_type=content_type)
# set library history # set library history
res = set_repo_history_limit(repo_id, days) if days != None:
if res == 0: res = set_repo_history_limit(repo_id, days)
messages.success(request, _(u'Settings saved.')) if res != 0:
return HttpResponse(json.dumps({'success': True}), return HttpResponse(json.dumps({'error': _(u'Failed to save settings on server')}),
content_type=content_type) status=400, content_type=content_type)
else:
return HttpResponse(json.dumps({'error': _(u'Failed to save settings on server')}), messages.success(request, _(u'Settings saved.'))
status=400, content_type=content_type) return HttpResponse(json.dumps({'success': True}),
content_type=content_type)
else: else:
return HttpResponse(json.dumps({'error': str(form.errors.values()[0])}), return HttpResponse(json.dumps({'error': str(form.errors.values()[0])}),
status=400, content_type=content_type) status=400, content_type=content_type)
@ -787,6 +789,23 @@ def myhome(request):
# Get all personal groups I joined. # Get all personal groups I joined.
joined_groups = get_personal_groups_by_user(request.user.username) joined_groups = get_personal_groups_by_user(request.user.username)
def get_abbrev_origin_path(repo_name, path):
if len(path) > 20:
abbrev_path = path[-20:]
return repo_name + '/...' + abbrev_path
else:
return repo_name + path
# compose abbrev origin path for display
sub_repos = []
if ENABLE_SUB_LIBRARY:
sub_repos = seafile_api.get_virtual_repos_by_owner(email)
for repo in sub_repos:
repo.abbrev_origin_path = get_abbrev_origin_path(repo.origin_repo_name,
repo.origin_path)
calculate_repo_last_modify(sub_repos)
sub_repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify))
# Personal repos that I owned. # Personal repos that I owned.
owned_repos = seafserv_threaded_rpc.list_owned_repos(email) owned_repos = seafserv_threaded_rpc.list_owned_repos(email)
calculate_repo_last_modify(owned_repos) calculate_repo_last_modify(owned_repos)
@ -888,6 +907,8 @@ def myhome(request):
"TRAFFIC_STATS_ENABLED": TRAFFIC_STATS_ENABLED, "TRAFFIC_STATS_ENABLED": TRAFFIC_STATS_ENABLED,
"traffic_stat": traffic_stat, "traffic_stat": traffic_stat,
"ENABLE_PAYMENT": getattr(settings, 'ENABLE_PAYMENT', False), "ENABLE_PAYMENT": getattr(settings, 'ENABLE_PAYMENT', False),
"ENABLE_SUB_LIBRARY": ENABLE_SUB_LIBRARY,
"sub_repos": sub_repos,
}, context_instance=RequestContext(request)) }, context_instance=RequestContext(request))
@login_required @login_required
@ -1515,6 +1536,39 @@ def repo_create(request):
return HttpResponseBadRequest(json.dumps(form.errors), return HttpResponseBadRequest(json.dumps(form.errors),
content_type=content_type) content_type=content_type)
@login_required
def create_sub_repo(request):
if not request.is_ajax() or request.method != 'POST':
return Http404
result = {}
content_type = 'application/json; charset=utf-8'
orig_repo_id = request.POST.get('orig_repo_id', '')
orig_path = request.POST.get('orig_path', '')
repo_name = request.POST.get('repo_name', '')
repo_desc = request.POST.get('repo_desc', '')
owner = request.user.username
if not orig_repo_id or not orig_path or not repo_name or not repo_desc:
return HttpResponseBadRequest("Invalid arguments", content_type=content_type)
try:
repo_id = seafile_api.create_virtual_repo(orig_repo_id, orig_path,
repo_name, repo_desc, owner)
except SearpcError, e:
result['error'] = e.msg
return HttpResponse(json.dumps(result), content_type=content_type)
result['success'] = True
result['repo_id'] = repo_id
repo_created.send(sender=None,
org_id=-1,
creator=owner,
repo_id=repo_id,
repo_name=repo_name)
return HttpResponse(json.dumps(result), content_type=content_type)
def render_file_revisions (request, repo_id): def render_file_revisions (request, repo_id):
"""List all history versions of a file.""" """List all history versions of a file."""
path = request.GET.get('p', '/') path = request.GET.get('p', '/')

View File

@ -20,6 +20,7 @@ from seahub.views import gen_path_link, get_user_permission, get_repo_dirents
from seahub.utils import get_ccnetapplet_root, is_file_starred, \ from seahub.utils import get_ccnetapplet_root, is_file_starred, \
gen_file_upload_url, get_httpserver_root, gen_shared_link, \ gen_file_upload_url, get_httpserver_root, gen_shared_link, \
EMPTY_SHA1, get_user_repos EMPTY_SHA1, get_user_repos
from seahub.settings import ENABLE_SUB_LIBRARY
# Get an instance of a logger # Get an instance of a logger
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -84,6 +85,7 @@ def get_unencry_rw_repos_by_user(username):
owned_repos, shared_repos, groups_repos, public_repos = get_user_repos(username) owned_repos, shared_repos, groups_repos, public_repos = get_user_repos(username)
accessible_repos = [] accessible_repos = []
for r in owned_repos: for r in owned_repos:
if not has_repo(accessible_repos, r) and not r.encrypted: if not has_repo(accessible_repos, r) and not r.encrypted:
r.has_subdir = check_has_subdir(r) r.has_subdir = check_has_subdir(r)
@ -165,7 +167,6 @@ def render_repo(request, repo):
Show repo direntries based on requested path Show repo direntries based on requested path
If user does not have permission to view repo If user does not have permission to view repo
return permission deny page return permission deny page
""" """
username = request.user.username username = request.user.username
user_perm = check_repo_access_permission(repo.id, username) user_perm = check_repo_access_permission(repo.id, username)
@ -242,6 +243,7 @@ def render_repo(request, repo):
'dir_shared_link': dir_shared_link, 'dir_shared_link': dir_shared_link,
'history_limit': history_limit, 'history_limit': history_limit,
'search_repo_id': search_repo_id, 'search_repo_id': search_repo_id,
'ENABLE_SUB_LIBRARY': ENABLE_SUB_LIBRARY,
}, context_instance=RequestContext(request)) }, context_instance=RequestContext(request))
@login_required @login_required