1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-20 19:08:21 +00:00

Added private share

This commit is contained in:
zhengxie
2013-06-24 17:56:31 +08:00
committed by llj
parent 02924f0b8c
commit b85ccbb24c
9 changed files with 302 additions and 30 deletions

View File

@@ -1,6 +1,8 @@
import datetime import datetime
from django.db import models from django.db import models
from seahub.utils import normalize_file_path, normalize_dir_path
class AnonymousShare(models.Model): class AnonymousShare(models.Model):
""" """
Model used for sharing repo to unregistered email. Model used for sharing repo to unregistered email.
@@ -21,3 +23,81 @@ class FileShare(models.Model):
ctime = models.DateTimeField(default=datetime.datetime.now) ctime = models.DateTimeField(default=datetime.datetime.now)
view_cnt = models.IntegerField(default=0) view_cnt = models.IntegerField(default=0)
s_type = models.CharField(max_length=2, db_index=True, default='f') # `f` or `d` s_type = models.CharField(max_length=2, db_index=True, default='f') # `f` or `d`
class PrivateFileDirShareManager(models.Manager):
def add_private_file_share(self, from_user, to_user, repo_id, path, perm):
"""
"""
path = normalize_file_path(path)
pfs = self.model(from_user=from_user, to_user=to_user, repo_id=repo_id,
path=path, s_type='f', permission=perm)
pfs.save(using=self._db)
return pfs
def get_private_share_in_file(self, username, repo_id, path):
"""Get a file that private shared to ``username``.
"""
path = normalize_file_path(path)
ret = super(PrivateFileDirShareManager, self).filter(
to_user=username, repo_id=repo_id, path=path, s_type='f')
return ret[0] if len(ret) > 0 else None
def add_private_dir_share(self, from_user, to_user, repo_id, path, perm):
"""
"""
path = normalize_dir_path(path)
pfs = self.model(from_user=from_user, to_user=to_user, repo_id=repo_id,
path=path, s_type='d', permission=perm)
pfs.save(using=self._db)
return pfs
def get_private_share_in_dir(self, username, repo_id, path):
"""Get a directory that private shared to ``username``.
"""
path = normalize_dir_path(path)
ret = super(PrivateFileDirShareManager, self).filter(
to_user=username, repo_id=repo_id, path=path, s_type='d')
return ret[0] if len(ret) > 0 else None
def delete_private_file_dir_share(self, from_user, to_user, repo_id, path):
"""
"""
super(PrivateFileDirShareManager, self).filter(
from_user=from_user, to_user=to_user, repo_id=repo_id,
path=path).delete()
def list_private_share_out_by_user(self, from_user):
"""List files/directories private shared from ``from_user``.
"""
return super(PrivateFileDirShareManager, self).filter(
from_user=from_user)
def list_private_share_in_by_user(self, to_user):
"""List files/directories private shared to ``to_user``.
"""
return super(PrivateFileDirShareManager, self).filter(
to_user=to_user)
def list_private_share_in_dirs_by_user_and_repo(self, to_user, repo_id):
"""List directories private shared to ``to_user`` base on ``repo_id``.
"""
return super(PrivateFileDirShareManager, self).filter(
to_user=to_user, repo_id=repo_id)
class PrivateFileDirShare(models.Model):
from_user = models.CharField(max_length=255, db_index=True)
to_user = models.CharField(max_length=255, db_index=True)
repo_id = models.CharField(max_length=36, db_index=True)
path = models.TextField()
permission = models.CharField(max_length=2) # `r` or `rw`
s_type = models.CharField(max_length=2, default='f') # `f` or `d`
objects = PrivateFileDirShareManager()

View File

@@ -109,6 +109,41 @@
<p>{% trans "You can share a folder or a file when you view a library, or share a file when you view it." %}</p> <p>{% trans "You can share a folder or a file when you view a library, or share a file when you view it." %}</p>
</div> </div>
{% endif %} {% endif %}
<h3>{% trans "Private shares" %}</h3>
{% if priv_shares %}
<table>
<tr>
<th width="45%">{% trans "File or Folder"%}</th>
<th width="25%">{% trans "Library"%}</th>
<th width="15%">{% trans "User"%}</th>
<th width="15%">{% trans "Operations"%}</th>
</tr>
{% for e in priv_shares %}
<tr>
{% if e.s_type == 'f' %}
<td><a href="{% url 'repo_view_file' e.repo_id %}?p={{ e.path|urlencode}}">{{e.file_or_dir}}</a></td>
{% else %}
<td><a href="{% url 'repo' e.repo_id %}?p={{ e.path|urlencode}}">{{e.file_or_dir}}</a></td>
{% endif %}
<td><a href="{% url 'repo' e.repo_id %}">{{e.repo.name}}</a></td>
{% if e.out_or_in == 'out' %}
<td>{{e.to_user|email2nickname}}</td>
{% else %}
<td>{{e.from_user|email2nickname}}</td>
{% endif %}
<td><a href="{% url 'rm_private_file_share' e.repo_id %}?from={{e.from_user|urlencode}}&to={{e.to_user|urlencode}}&p={{e.path|urlencode}}" class="op">Unshare</a></td>
</tr>
{% endfor %}
</table>
{% else%}
<div class="empty-tips">
<h2 class="center-contents">{% trans "You don't have any private shared files/folders" %}</h2>
<p>{% trans "You can share a single folder or file to a registered user if you don't want to share hole library to he/she." %}</p>
</div>
{% endif %}
{% endblock %} {% endblock %}
{% block extra_script %} {% block extra_script %}

View File

@@ -24,7 +24,7 @@ from seaserv import seafserv_threaded_rpc, get_repo, ccnet_rpc, \
list_inner_pub_repos_by_owner, remove_share list_inner_pub_repos_by_owner, remove_share
from forms import RepoShareForm, FileLinkShareForm from forms import RepoShareForm, FileLinkShareForm
from models import AnonymousShare from models import AnonymousShare, FileShare, PrivateFileDirShare
from signals import share_repo_to_user_successful from signals import share_repo_to_user_successful
from settings import ANONYMOUS_SHARE_COOKIE_TIMEOUT from settings import ANONYMOUS_SHARE_COOKIE_TIMEOUT
from tokens import anon_share_token_generator from tokens import anon_share_token_generator
@@ -32,7 +32,6 @@ from seahub.auth.decorators import login_required
from seahub.base.accounts import User from seahub.base.accounts import User
from seahub.contacts.models import Contact from seahub.contacts.models import Contact
from seahub.contacts.signals import mail_sended from seahub.contacts.signals import mail_sended
from seahub.share.models import FileShare
from seahub.views import validate_owner, is_registered_user from seahub.views import validate_owner, is_registered_user
from seahub.utils import render_permission_error, string2list, render_error, \ from seahub.utils import render_permission_error, string2list, render_error, \
gen_token, gen_shared_link, gen_dir_share_link, gen_file_share_link, \ gen_token, gen_shared_link, gen_dir_share_link, gen_file_share_link, \
@@ -325,11 +324,26 @@ def share_admin(request):
fs.repo = r fs.repo = r
p_fileshares.append(fs) p_fileshares.append(fs)
# Private share out/in files/directories
priv_share_out = PrivateFileDirShare.objects.list_private_share_out_by_user(username)
for e in priv_share_out:
e.file_or_dir = os.path.basename(e.path.rstrip('/'))
e.out_or_in = 'out'
e.repo = seafile_api.get_repo(e.repo_id)
priv_share_in = PrivateFileDirShare.objects.list_private_share_in_by_user(username)
for e in priv_share_in:
e.file_or_dir = os.path.basename(e.path.rstrip('/'))
e.out_or_in = 'in'
e.repo = seafile_api.get_repo(e.repo_id)
priv_shares = list(priv_share_out) + list(priv_share_in)
return render_to_response('repo/share_admin.html', { return render_to_response('repo/share_admin.html', {
"org": None, "org": None,
"shared_repos": shared_repos, "shared_repos": shared_repos,
# "out_links": out_links, # "out_links": out_links,
"fileshares": p_fileshares, "fileshares": p_fileshares,
"priv_shares": priv_shares,
}, context_instance=RequestContext(request)) }, context_instance=RequestContext(request))
@login_required @login_required

View File

@@ -117,7 +117,7 @@
<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" data-path="{{path}}{{dirent.obj_name}}">{% trans "Share" %}</a>
{% endif %} {% endif %}
{% if ENABLE_SUB_LIBRARY and not repo.is_virtual %} {% 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> <a class="op create-sub-repo" href="#" data-name="{{ dirent.obj_name }}">{% trans "Sub-library" %}</a>
@@ -166,7 +166,7 @@
{% if user_perm == 'rw' %} {% if user_perm == 'rw' %}
<a class="op update-file" data-target="{{ path }}{{dirent.obj_name}}" href="#">{% trans "Update"%}</a> <a class="op update-file" data-target="{{ path }}{{dirent.obj_name}}" href="#">{% trans "Update"%}</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 }}">{% trans "Share" %}</a> <a class="op file-share" href="#" data-name="{{ dirent.obj_name }}" data-link="{{ dirent.sharelink }}" data-token="{{ dirent.sharetoken }}" data-type="f" data-path="{{path}}{{dirent.obj_name}}" >{% trans "Share" %}</a>
{% endif %} {% endif %}
{% endif %} {% endif %}
</div> </div>
@@ -328,6 +328,29 @@
<div id="file-share" class="hide"> <div id="file-share" class="hide">
<h3>{% trans 'Share' %} <span class="op-target"></span></h3> <h3>{% trans 'Share' %} <span class="op-target"></span></h3>
<div id="repo-share-tabs">
<ul id="repo-share-tabs-nav">
<li><a href="#private-share">{% trans "Private share" %}</a></li>
<li><a href="#shared-link">{% trans "Shared link" %}</a></li>
</ul>
<div id="private-share">
<form id="private-share-form" method="post" action="{% url 'private_file_share' repo.id %}">{% csrf_token %}
<textarea id="emails" name="emails" class="w100" placeholder="{% trans "Emails seperated by ','"%}"></textarea>
<select name="perm" class="share-permission-select w100">
<option value="rw" selected="selected">{% trans "Read-Write"%}</option>
<option value="r">{% trans "Read-Only"%}</option>
</select>
<input type="hidden" name="repo_id" value="" />
<input type="hidden" name="s_type" value="" />
<input type="hidden" name="path" value="" />
<p class="tip">{% trans 'Tip: must be a registered user.' %}</p>
<input type="submit" value="{% trans "Submit"%}" />
</form>
</div> <!--/#private-share-->
<div id="shared-link">
<p>{% trans 'Link: ' %}<input type="text" readonly="readonly" id="shared-link-text" /></p> <p>{% trans 'Link: ' %}<input type="text" readonly="readonly" id="shared-link-text" /></p>
<button id="send-link">{% trans 'Send' %}</button> <button id="send-link">{% trans 'Send' %}</button>
<form id="link-send-form" action="" method="post" class="hide">{% csrf_token %} <form id="link-send-form" action="" method="post" class="hide">{% csrf_token %}
@@ -338,7 +361,9 @@
<p class="error hide"></p> <p class="error hide"></p>
<p id="sending" class="hide">{% trans "Sending..."%}</p> <p id="sending" class="hide">{% trans "Sending..."%}</p>
</form> </form>
</div> </div> <!--/#shared-link-->
</div> <!--/#repo-share-tabs-->
</div> <!--/#file-share-->
{% with attach_type='dir' %} {% with attach_type='dir' %}
{% include "snippets/group_recommend_form.html" %} {% include "snippets/group_recommend_form.html" %}
@@ -656,6 +681,15 @@ $('.file-star').click(function() {
//file share //file share
$('.file-share').click(function() { $('.file-share').click(function() {
$("#private-share-form input[name=s_type]").val($(this).data('type'));
$("#private-share-form input[name=path]").val($(this).data('path'));
var contacts = [];
{% for contact in contacts %}
contact_email = '{{ contact.contact_email }}';
contacts.push({value:contact_email, label:contact_email});
{% endfor %}
addAutocomplete('#emails', '#private-share-form', contacts);
var filename = $(this).data('name'); var filename = $(this).data('name');
function showPopup(link) { function showPopup(link) {
$('#file-share .op-target').html(trimFilename(filename, 30)); $('#file-share .op-target').html(trimFilename(filename, 30));
@@ -663,6 +697,7 @@ $('.file-share').click(function() {
$('#main').append('<p id="linkwidth" class="hide">' + link + '</p>'); $('#main').append('<p id="linkwidth" class="hide">' + link + '</p>');
$('#shared-link-text').css({'width':$('#linkwidth').width() + 2}); $('#shared-link-text').css({'width':$('#linkwidth').width() + 2});
$('#file-share').modal({'focus':false}); // in ff: if 'focus' is true, 'shared-link-text' gets the focus $('#file-share').modal({'focus':false}); // in ff: if 'focus' is true, 'shared-link-text' gets the focus
$("#repo-share-tabs").tabs();
$('#linkwidth').remove(); $('#linkwidth').remove();
$('#simplemodal-container').css({'height':'auto'}); $('#simplemodal-container').css({'height':'auto'});
} }

View File

@@ -42,7 +42,6 @@
</ul> </ul>
</div> </div>
</div> </div>
<div class="bot"> <div class="bot">
<select name="permission" class="share-permission-select w100"> <select name="permission" class="share-permission-select w100">
<option value="rw" selected="selected">{% trans "Read-Write"%}</option> <option value="rw" selected="selected">{% trans "Read-Write"%}</option>

View File

@@ -5,7 +5,7 @@ from django.conf import settings
from seahub.views import * from seahub.views import *
from seahub.views.file import view_file, view_history_file, view_trash_file,\ from seahub.views.file import view_file, view_history_file, view_trash_file,\
view_snapshot_file, file_edit, view_shared_file, view_file_via_shared_dir,\ view_snapshot_file, file_edit, view_shared_file, view_file_via_shared_dir,\
text_diff text_diff, private_file_share, rm_private_file_share
from seahub.views.repo import repo, repo_history_view from seahub.views.repo import repo, repo_history_view
from notifications.views import notification_list from notifications.views import notification_list
from group.views import group_list from group.views import group_list
@@ -80,7 +80,9 @@ urlpatterns = patterns('',
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/trash/files/$', view_trash_file, name="view_trash_file"), url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/trash/files/$', view_trash_file, name="view_trash_file"),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/snapshot/files/$', view_snapshot_file, name="view_snapshot_file"), url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/snapshot/files/$', view_snapshot_file, name="view_snapshot_file"),
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})/privshare/$', private_file_share, name='private_file_share'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/privshare/remove/$', rm_private_file_share, name='rm_private_file_share'),
url(r'^repo/(?P<repo_id>[-0-9a-f]{36})/(?P<obj_id>[0-9a-f]{40})/$', 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'^repo/create_sub_repo/$', create_sub_repo, name='create_sub_repo'),

View File

@@ -166,6 +166,18 @@ def calculate_repo_last_modify(repo_list):
cmmts = get_commits(repo.id, 0, 1) cmmts = get_commits(repo.id, 0, 1)
repo.latest_modify = cmmts[0].ctime if cmmts else 0 repo.latest_modify = cmmts[0].ctime if cmmts else 0
def normalize_dir_path(path):
"""Add '/' at the end of directory path if necessary.
"""
if path[-1] != '/':
path = path + '/'
return path
def normalize_file_path(path):
"""Remove '/' at the end of file path if necessary.
"""
return path.rstrip('/')
def check_filename_with_rename(repo_id, parent_dir, filename): def check_filename_with_rename(repo_id, parent_dir, filename):
cmmts = get_commits(repo_id, 0, 1) cmmts = get_commits(repo_id, 0, 1)
latest_commit = cmmts[0] if cmmts else None latest_commit = cmmts[0] if cmmts else None

View File

@@ -13,6 +13,7 @@ import chardet
import logging import logging
from django.contrib.sites.models import Site, RequestSite from django.contrib.sites.models import Site, RequestSite
from django.contrib import messages
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db.models import F from django.db.models import F
from django.http import HttpResponse, HttpResponseBadRequest, Http404, \ from django.http import HttpResponse, HttpResponseBadRequest, Http404, \
@@ -23,6 +24,7 @@ from django.template.loader import render_to_string
from django.utils.hashcompat import md5_constructor from django.utils.hashcompat import md5_constructor
from django.utils.http import urlquote from django.utils.http import urlquote
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views.decorators.http import require_POST
from django.template.defaultfilters import filesizeformat from django.template.defaultfilters import filesizeformat
from seaserv import seafile_api from seaserv import seafile_api
@@ -36,7 +38,7 @@ from seahub.auth.decorators import login_required
from seahub.base.decorators import repo_passwd_set_required from seahub.base.decorators import repo_passwd_set_required
from seahub.base.models import UuidObjidMap from seahub.base.models import UuidObjidMap
from seahub.contacts.models import Contact from seahub.contacts.models import Contact
from seahub.share.models import FileShare from seahub.share.models import FileShare, PrivateFileDirShare
from seahub.wiki.utils import get_wiki_dirent from seahub.wiki.utils import get_wiki_dirent
from seahub.wiki.models import WikiDoesNotExist, WikiPageMissing from seahub.wiki.models import WikiDoesNotExist, WikiPageMissing
from seahub.utils import get_httpserver_root, show_delete_days, render_error, \ from seahub.utils import get_httpserver_root, show_delete_days, render_error, \
@@ -45,8 +47,8 @@ from seahub.utils import get_httpserver_root, show_delete_days, render_error, \
is_textual_file, show_delete_days, mkstemp, EMPTY_SHA1, HtmlDiff is_textual_file, show_delete_days, mkstemp, EMPTY_SHA1, HtmlDiff
from seahub.utils.file_types import (IMAGE, PDF, IMAGE, DOCUMENT, MARKDOWN, \ from seahub.utils.file_types import (IMAGE, PDF, IMAGE, DOCUMENT, MARKDOWN, \
TEXT, SF) TEXT, SF)
from seahub.utils import HAS_OFFICE_CONVERTER from seahub.utils import HAS_OFFICE_CONVERTER
from seahub.views import is_registered_user
if HAS_OFFICE_CONVERTER: if HAS_OFFICE_CONVERTER:
from seahub.utils import query_office_convert_status, query_office_file_pages, \ from seahub.utils import query_office_convert_status, query_office_file_pages, \
@@ -147,19 +149,41 @@ def repo_file_get(raw_path, file_enc):
return err, file_content, encoding return err, file_content, encoding
def get_file_view_path_and_perm(request, repo_id, obj_id, filename): def check_file_access_permission(username, repo_id, path):
"""Check user has permission to view the file.
1. check whether this file is private shared.
2. if failed, check whether the parent of this directory is private shared.
"""
pfs = PrivateFileDirShare.objects.get_private_share_in_file(username,
repo_id, path)
if pfs is None:
dirs = PrivateFileDirShare.objects.list_private_share_in_dirs_by_user_and_repo(username, repo_id)
for e in dirs:
if path.startswith(e.path):
return e.permission
return None
else:
return pfs.permission
def check_repo_access_permission(repo_id, username):
return seafile_api.check_repo_access_permission(repo_id, username)
def get_file_view_path_and_perm(request, repo_id, obj_id, path):
""" """
Return raw path of a file and the permission to view file. Return raw path of a file and the permission to view file.
""" """
username = request.user.username username = request.user.username
# check permission filename = os.path.basename(path)
perm = get_user_permission(request, repo_id)
if perm: user_perm = check_file_access_permission(username, repo_id, path) or \
check_repo_access_permission(repo_id, username)
if user_perm is None:
return ('', user_perm)
else:
# Get a token to visit file # Get a token to visit file
token = web_get_access_token(repo_id, obj_id, 'view', username) token = web_get_access_token(repo_id, obj_id, 'view', username)
return (gen_file_get_url(token, filename), perm) return (gen_file_get_url(token, filename), user_perm)
else:
return ('', perm)
def handle_textual_file(request, filetype, raw_path, ret_dict): def handle_textual_file(request, filetype, raw_path, ret_dict):
# encoding option a user chose # encoding option a user chose
@@ -284,7 +308,7 @@ def view_file(request, repo_id):
if not repo: if not repo:
raise Http404 raise Http404
path = request.GET.get('p', '/') path = request.GET.get('p', '/').rstrip('/')
obj_id = get_file_id_by_path(repo_id, path) obj_id = get_file_id_by_path(repo_id, path)
if not obj_id: if not obj_id:
return render_error(request, _(u'File does not exist')) return render_error(request, _(u'File does not exist'))
@@ -296,7 +320,7 @@ def view_file(request, repo_id):
# Check whether user has permission to view file and get file raw path, # Check whether user has permission to view file and get file raw path,
# render error page if permission is deny. # render error page if permission is deny.
raw_path, user_perm = get_file_view_path_and_perm(request, repo_id, raw_path, user_perm = get_file_view_path_and_perm(request, repo_id,
obj_id, u_filename) obj_id, path)
if not user_perm: if not user_perm:
return render_permission_error(request, _(u'Unable to view file')) return render_permission_error(request, _(u'Unable to view file'))
@@ -461,7 +485,7 @@ def view_history_file_common(request, repo_id, ret_dict):
# Check whether user has permission to view file and get file raw path, # Check whether user has permission to view file and get file raw path,
# render error page if permission is deny. # render error page if permission is deny.
raw_path, user_perm = get_file_view_path_and_perm(request, repo_id, raw_path, user_perm = get_file_view_path_and_perm(request, repo_id,
obj_id, u_filename) obj_id, path)
request.user_perm = user_perm request.user_perm = user_perm
# get file type and extension # get file type and extension
@@ -1030,3 +1054,55 @@ def office_convert_query_page_num(request):
ret['error'] = str(e) ret['error'] = str(e)
return HttpResponse(json.dumps(ret), content_type=content_type) return HttpResponse(json.dumps(ret), content_type=content_type)
###### private file/dir shares
@require_POST
def private_file_share(request, repo_id):
emails = request.POST.get('emails', '')
s_type = request.POST.get('s_type', '')
path = request.POST.get('path', '')
perm = request.POST.get('perm', 'r')
file_or_dir = os.path.basename(path.rstrip('/'))
username = request.user.username
for email in [e.strip() for e in emails.split(',') if e.strip()]:
if not is_registered_user(email):
messages.error(request, _('Failed to share to "%s", user not found.') % email)
continue
if s_type == 'f':
PrivateFileDirShare.objects.add_private_file_share(
username, email, repo_id, path, perm)
elif s_type == 'd':
PrivateFileDirShare.objects.add_private_dir_share(
username, email, repo_id, path, perm)
else:
assert False # todo
messages.success(request, _('Successfully shared %s.') % file_or_dir)
next = request.META.get('HTTP_REFERER', None)
if not next:
next = SITE_ROOT
return HttpResponseRedirect(next)
@login_required
def rm_private_file_share(request, repo_id):
"""Remove private file shares.
"""
from_user = request.GET.get('from', '')
to_user = request.GET.get('to', '')
username = request.user.username
if username == from_user or username == to_user:
path = request.GET.get('p')
file_or_dir = os.path.basename(path.rstrip('/'))
PrivateFileDirShare.objects.delete_private_file_dir_share(
from_user, to_user, repo_id, path)
messages.success(request, _('Successfully unshared "%s".') % file_or_dir)
else:
messages.error(request, _("You don't have permission to unshared %s.") % file_or_dir)
next = request.META.get('HTTP_REFERER', None)
if not next:
next = SITE_ROOT
return HttpResponseRedirect(next)

View File

@@ -15,7 +15,7 @@ from seaserv import seafile_api, MAX_UPLOAD_FILE_SIZE
from seahub.auth.decorators import login_required from seahub.auth.decorators import login_required
from seahub.contacts.models import Contact from seahub.contacts.models import Contact
from seahub.forms import RepoPassowrdForm from seahub.forms import RepoPassowrdForm
from seahub.share.models import FileShare from seahub.share.models import FileShare, PrivateFileDirShare
from seahub.views import gen_path_link, get_user_permission, get_repo_dirents 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_dir_share_link, \ gen_file_upload_url, get_httpserver_root, gen_dir_share_link, \
@@ -40,6 +40,23 @@ def list_dir_by_commit_and_path(commit, path):
def is_password_set(repo_id, username): def is_password_set(repo_id, username):
return seafile_api.is_password_set(repo_id, username) return seafile_api.is_password_set(repo_id, username)
def check_dir_access_permission(username, repo_id, path):
"""Check user has permission to view the directory.
1. check whether this directory is private shared.
2. if failed, check whether the parent of this directory is private shared.
"""
pfs = PrivateFileDirShare.objects.get_private_share_in_dir(username,
repo_id, path)
if pfs is None:
dirs = PrivateFileDirShare.objects.list_private_share_in_dirs_by_user_and_repo(username, repo_id)
for e in dirs:
if path.startswith(e.path):
return e.permission
return None
else:
return pfs.permission
def check_repo_access_permission(repo_id, username): def check_repo_access_permission(repo_id, username):
return seafile_api.check_repo_access_permission(repo_id, username) return seafile_api.check_repo_access_permission(repo_id, username)
@@ -169,7 +186,9 @@ def render_repo(request, 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) path = get_path_from_request(request)
user_perm = check_dir_access_permission(username, repo.id, path) or \
check_repo_access_permission(repo.id, username)
if user_perm is None: if user_perm is None:
return render_to_response('repo_access_deny.html', { return render_to_response('repo_access_deny.html', {
'repo': repo, 'repo': repo,
@@ -189,7 +208,6 @@ def render_repo(request, repo):
protocol = request.is_secure() and 'https' or 'http' protocol = request.is_secure() and 'https' or 'http'
domain = RequestSite(request).domain domain = RequestSite(request).domain
path = get_path_from_request(request)
contacts = Contact.objects.get_contacts_by_user(username) contacts = Contact.objects.get_contacts_by_user(username)
accessible_repos = [repo] if repo.encrypted else get_unencry_rw_repos_by_user(username) accessible_repos = [repo] if repo.encrypted else get_unencry_rw_repos_by_user(username)
@@ -278,7 +296,9 @@ def repo_history_view(request, repo_id):
raise Http404 raise Http404
username = request.user.username username = request.user.username
user_perm = check_repo_access_permission(repo.id, username) path = get_path_from_request(request)
user_perm = check_dir_access_permission(username, repo.id, path) or \
check_repo_access_permission(repo.id, username)
if user_perm is None: if user_perm is None:
return render_to_response('repo_access_deny.html', { return render_to_response('repo_access_deny.html', {
'repo': repo, 'repo': repo,
@@ -298,7 +318,6 @@ def repo_history_view(request, repo_id):
if not current_commit: if not current_commit:
current_commit = get_commit(repo.head_cmmt_id) current_commit = get_commit(repo.head_cmmt_id)
path = get_path_from_request(request)
file_list, dir_list = get_repo_dirents(request, repo.id, current_commit, path) file_list, dir_list = get_repo_dirents(request, repo.id, current_commit, path)
zipped = get_nav_path(path, repo.name) zipped = get_nav_path(path, repo.name)
search_repo_id = None if repo.encrypted else repo.id search_repo_id = None if repo.encrypted else repo.id