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

Add file shared link, and modify url viewing file

This commit is contained in:
xiez
2012-07-11 22:39:36 +08:00
parent c3296df1c1
commit d66938cce0
10 changed files with 547 additions and 85 deletions

View File

@@ -32,3 +32,13 @@ class AddUserForm(forms.Form):
if self.cleaned_data['password1'] != self.cleaned_data['password2']: if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError(_("The two password fields didn't match.")) raise forms.ValidationError(_("The two password fields didn't match."))
return self.cleaned_data return self.cleaned_data
class FileLinkShareForm(forms.Form):
"""
Form for sharing file shared link to emails.
"""
email = forms.CharField(max_length=512)
file_shared_link = forms.CharField(max_length=40)

View File

@@ -466,6 +466,7 @@ table img {
margin-top:8px; margin-top:8px;
} }
/*repo-share-form*/ /*repo-share-form*/
#email,
#email_or_group, #email_or_group,
#share-link, #share-link,
#added-member-name { #added-member-name {
@@ -653,3 +654,4 @@ table img {
max-width: 550px; max-width: 550px;
max-height: 550px; max-height: 550px;
} }

View File

@@ -1,8 +1,21 @@
import datetime
from django.db import models from django.db import models
class AnonymousShare(models.Model): class AnonymousShare(models.Model):
"""
Model used for sharing repo to unregistered email.
"""
repo_owner = models.EmailField(max_length=255) repo_owner = models.EmailField(max_length=255)
repo_id = models.CharField(max_length=36) repo_id = models.CharField(max_length=36)
anonymous_email = models.EmailField(max_length=255) anonymous_email = models.EmailField(max_length=255)
token = models.CharField(max_length=25, unique=True) token = models.CharField(max_length=25, unique=True)
class FileShare(models.Model):
"""
Model used for file share link.
"""
username = models.EmailField(max_length=255)
repo_id = models.CharField(max_length=36, db_index=True)
path = models.TextField()
token = models.CharField(max_length=10, unique=True)
ctime = models.DateTimeField(default=datetime.datetime.now)

View File

@@ -153,9 +153,9 @@
<tr> <tr>
<td class="icon-container"><img src="{{ MEDIA_URL }}img/{{ dirent.obj_name|file_icon_filter }}" alt="文件" /></td> <td class="icon-container"><img src="{{ MEDIA_URL }}img/{{ dirent.obj_name|file_icon_filter }}" alt="文件" /></td>
{% if view_history %} {% if view_history %}
<td><a class="op" href="{{ SITE_ROOT }}repo/{{ repo.props.id }}/view/{{ dirent.props.obj_id }}/?commit_id={{ current_commit.id }}&file_name={{ dirent.props.obj_name }}&p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{{ dirent.props.obj_name }}</a></td> <td><a class="op" href="{{ SITE_ROOT }}repo/{{ repo.props.id }}/files/?obj_id={{ dirent.props.obj_id }}&commit_id={{ current_commit.id }}&p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{{ dirent.props.obj_name }}</a></td>
{% else %} {% else %}
<td><a class="op" href="{{ SITE_ROOT }}repo/{{ repo.props.id }}/view/{{ dirent.props.obj_id }}/?file_name={{ dirent.props.obj_name }}&p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{{ dirent.props.obj_name }}</a></td> <td><a class="op" href="{{ SITE_ROOT }}repo/{{ repo.props.id }}/files/?p={{ path|urlencode }}{{ dirent.obj_name|urlencode }}">{{ dirent.props.obj_name }}</a></td>
{% endif %} {% endif %}
<td>{{ dirent.file_size|filesizeformat }}</td> <td>{{ dirent.file_size|filesizeformat }}</td>

View File

@@ -25,6 +25,17 @@
<p><a href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=view" target="_blank">查看原始文件</a></p> <p><a href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=view" target="_blank">查看原始文件</a></p>
<p><a href="{{ SITE_ROOT }}repo/file_revisions/{{ repo.id }}/?p={{ path|urlencode }}">查看所有历史版本</a></p> <p><a href="{{ SITE_ROOT }}repo/file_revisions/{{ repo.id }}/?p={{ path|urlencode }}">查看所有历史版本</a></p>
<p><a href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=download" target="_blank">下载文件</a></p> <p><a href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=download" target="_blank">下载文件</a></p>
{% if not view_history %}
<h3>共享</h3>
<p class="shared-link">
<span class="hide">链接:{{ file_shared_link }}</span>
<a href="#" data="{{ SITE_ROOT }}sharedlink/get/?repo_id={{ repo.id }}&p={{ path|urlencode }}&file_name={{ file_name }}" class="get-shared-link">获取分享链接</a></p>
<div class="link-op hide">
<a href="#" class="send-shared-link">发送</a>
<a href="#" data="{{ SITE_ROOT }}sharedlink/remove/?t={{ fileshare.token }}" class="remove-shared-link">删除</a>
</div>
{% endif %}
</div> </div>
<div class="main fleft"> <div class="main fleft">
@@ -44,17 +55,53 @@
</p> </p>
<pre id="file-content">正在读取文件内容...</pre> <pre id="file-content">正在读取文件内容...</pre>
</div> </div>
<form id="link-send-form" action="" method="post" name="link-send-form" class="hide">
<label>邮箱:</label><br />
<textarea id="email" name="email"></textarea><br />
<input id="file_shared_link" type="hidden" name="file_shared_link" value="{{ file_shared_link }}" />
<p class="error hide">输入不能为空。</p>
<p class="success hide"></p>
<p class="sending hide">发送中...</p>
<input type="submit" value="提交" id="share-submit-btn" />
</form>
{% endblock %} {% endblock %}
{% block extra_script %} {% block extra_script %}
<script type="text/javascript"> <script type="text/javascript">
$(window).load(function() { function showLink() {
$('.shared-link a').addClass('hide');
$('.shared-link span').removeClass('hide');
$('.link-op').removeClass('hide');
}
function hideLink() {
$('.shared-link span').addClass('hide');
$('.link-op').addClass('hide');
$('.shared-link a').removeClass('hide');
}
$(window).load(function() {
var can_preview = "{{ can_preview }}"; var can_preview = "{{ can_preview }}";
var view_history = "{{ view_history }}";
var url = "";
if (view_history == 'True') {
url = "{{ SITE_ROOT }}repo/{{ repo.id }}/file/get/?obj_id={{ obj_id }}&p={{ path }}&t={{ token }}&u={{ request.user.username }}";
} else {
url = "{{ SITE_ROOT }}repo/{{ repo.id }}/file/get/?p={{ path }}&t={{ token }}&u={{ request.user.username }}";
}
var filetype = "{{ filetype }}"; var filetype = "{{ filetype }}";
var t = "{{ fileshare.token }}";
if (t) {
showLink();
} else {
hideLink();
}
if (can_preview == 'True' && filetype == 'Document') { if (can_preview == 'True' && filetype == 'Document') {
$.ajax({ $.ajax({
url: '{{ SITE_ROOT }}repo/{{ repo.id }}/view/{{ obj_id }}/?file_name={{ file_name }}&t={{ token }}', url: url,
dataType: 'json', dataType: 'json',
cache: false, cache: false,
contentType: 'application/json; charset=utf-8', contentType: 'application/json; charset=utf-8',
@@ -74,7 +121,114 @@
} else { } else {
$('#file-content').html('无法识别该文件格式,<a class="op" href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=download">下载文件</a>。'); $('#file-content').html('无法识别该文件格式,<a class="op" href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=download">下载文件</a>。');
} }
});
$('.get-shared-link').click(function() {
var url = $(this).attr('data');
$.ajax({
url: url,
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8',
success: function(data) {
if (data.length > 0) {
var t = data[0]['token'];
var shared_link = '{{ protocol }}://{{ domain }}{{ SITE_ROOT }}f/' + t + '/';
$('.shared-link span').html('链接:' + shared_link);
$('.remove-shared-link').attr('data', '{{ SITE_ROOT }}sharedlink/remove/?t='+t);
showLink();
}
},
error: function(xhr, ajaxOptions, thrownError) {
var jsonVal = jQuery.parseJSON(xhr.responseText);
$('.get-shared-link').html(jsonVal[0]['error']);
}
}); });
return false;
});
$('.remove-shared-link').click(function() {
var url = $(this).attr('data');
$.ajax({
url: url,
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8',
success: function(data) {
hideLink();
}
});
return false;
});
$('.send-shared-link').click(function() {
$("#link-send-form").modal({appendTo: "#main"});
});
$("#link-send-form").submit(function(event) {
// clear error and sucess msg
$('.error').html("").addClass('hide');
$('.success').html("").addClass('hide');
$('.sending').removeClass('hide');
$('#simplemodal-container').css('height', $('#link-send-form').height());
var form = $(this),
file_shared_link = form.children('input[name="file_shared_link"]').val(),
email = form.children('textarea[name="email"]').val();
if (email && email.length <= 512) {
// prepare django csrf token
$.ajaxSetup({
beforeSend: function(xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
$.ajax({
type: "POST",
url: "{{ SITE_ROOT }}sharedlink/send/",
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8',
data: "file_shared_link="+file_shared_link+"&email="+email,
success: function(data) {
form.children('.error').addClass('hide');
form.children('.sending').addClass('hide');
form.children('.success').html(data[0]['msg']).removeClass('hide');
$('#simplemodal-container').css('height', $('#link-send-form').height());
},
error: function(xhr, ajaxOptions, thrownError) {
var jsonVal = jQuery.parseJSON(xhr.responseText);
form.children('.success').addClass('hide');
form.children('.sending').addClass('hide');
form.children('.error').html(jsonVal[0]['error']).removeClass('hide');
$('#simplemodal-container').css('height', $('#link-send-form').height());
}
});
} else {
form.children('.success').html("").addClass('hide');
form.children('.sending').addClass('hide');
form.children('.error').removeClass('hide');
}
return false;
});
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,12 @@
{% autoescape off %}
亲爱的 {{ to_email }}
{{ email }} 在SeaCloud上共享了一个文件给你请点击以下链接查看
{{ file_shared_link }}
感谢使用我们的网站!
Seafile团队
{% endautoescape %}

View File

@@ -0,0 +1,54 @@
{% extends "myhome_base.html" %}
{% load seahub_tags %}
{% block main_panel %}
<h2 class="subject">
{{ file_name }}<br />
<span class="latest-commit-time-author">共享者:{{ username }}</span>
</h2>
<div class="side fright">
<h3>操作</h3>
<p><a href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=view" target="_blank">查看原始文件</a></p>
<p><a href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=download" target="_blank">下载文件</a></p>
</div>
<div class="main fleft">
<pre id="file-content">正在读取文件内容...</pre>
</div>
{% endblock %}
{% block extra_script %}
<script type="text/javascript">
$(window).load(function() {
var can_preview = "{{ can_preview }}";
var url = "{{ SITE_ROOT }}repo/{{ repo.id }}/file/get/?t={{ access_token }}&p={{ path }}&u={{ username }}";
var filetype = "{{ filetype }}";
if (can_preview == 'True' && filetype == 'Document') {
$.ajax({
url: url,
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8',
success: function(data) {
if (data.length > 0) {
$('#file-content').html(data[0]['content']);
}
},
error: function(xhr, ajaxOptions, thrownError) {
var jsonVal = jQuery.parseJSON(xhr.responseText);
$('#file-content').html(jsonVal[0]['error']);
}
});
return false;
} else if (can_preview == 'True' && filetype == 'Image') {
$('#file-content').replaceWith('<img class="img-preview" src="{{ raw_path }}"></img>');
} else {
$('#file-content').html('无法识别该文件格式,<a class="op" href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=download">下载文件</a>。');
}
});
</script>
{% endblock %}

16
urls.py
View File

@@ -6,13 +6,14 @@ from seahub.views import root, peers, myhome, \
repo, repo_history, modify_token, remove_repo, sys_seafadmin, sys_useradmin, \ repo, repo_history, modify_token, remove_repo, sys_seafadmin, sys_useradmin, \
org_seafadmin, org_useradmin, org_group_admin, org_remove, \ org_seafadmin, org_useradmin, org_group_admin, org_remove, \
activate_user, user_add, user_remove, sys_group_admin, sys_org_admin, \ activate_user, user_add, user_remove, sys_group_admin, sys_org_admin, \
ownerhome, repo_history_revert, \ ownerhome, repo_history_revert, repo_file_get, \
user_info, repo_set_access_property, repo_access_file, \ user_info, repo_set_access_property, repo_access_file, \
repo_remove_share, repo_download, org_info, repo_view_file, \ repo_remove_share, repo_download, org_info, repo_view_file, \
seafile_access_check, back_local, repo_history_changes, \ seafile_access_check, back_local, repo_history_changes, \
repo_upload_file, file_upload_progress, file_upload_progress_page, get_subdir, file_move, \ repo_upload_file, file_upload_progress, file_upload_progress_page, \
repo_new_dir, repo_rename_file, validate_filename, \ get_subdir, file_move, repo_new_dir, repo_rename_file, validate_filename, \
repo_create, repo_update_file, file_revisions repo_create, repo_update_file, file_revisions, \
get_shared_link, view_shared_file, remove_shared_link, send_shared_link
from seahub.notifications.views import notification_list from seahub.notifications.views import notification_list
from seahub.share.views import share_admin from seahub.share.views import share_admin
from seahub.group.views import group_list from seahub.group.views import group_list
@@ -42,6 +43,10 @@ urlpatterns = patterns('',
(r'^share/', include('share.urls')), (r'^share/', include('share.urls')),
url(r'^shareadmin/$', share_admin, name='share_admin'), url(r'^shareadmin/$', share_admin, name='share_admin'),
(r'^shareadmin/removeshare/$', repo_remove_share), (r'^shareadmin/removeshare/$', repo_remove_share),
(r'^sharedlink/get/$', get_shared_link),
(r'^sharedlink/remove/$', remove_shared_link),
(r'^sharedlink/send/$', send_shared_link),
(r'^f/(?P<token>[^/]+)/$', view_shared_file),
(r'^file_upload_progress/$', file_upload_progress), (r'^file_upload_progress/$', file_upload_progress),
(r'^file_upload_progress_page/$', file_upload_progress_page), (r'^file_upload_progress_page/$', file_upload_progress_page),
@@ -61,7 +66,8 @@ urlpatterns = patterns('',
# (r'^repo/removefetched/(?P<user_id>[^/]+)/(?P<repo_id>[^/]+)/$', remove_fetched_repo), # (r'^repo/removefetched/(?P<user_id>[^/]+)/(?P<repo_id>[^/]+)/$', remove_fetched_repo),
# (r'^repo/setap/(?P<repo_id>[^/]+)/$', repo_set_access_property), # (r'^repo/setap/(?P<repo_id>[^/]+)/$', repo_set_access_property),
url(r'^repo/(?P<repo_id>[^/]+)/(?P<obj_id>[^/]+)/$', repo_access_file, name='repo_access_file'), url(r'^repo/(?P<repo_id>[^/]+)/(?P<obj_id>[^/]+)/$', repo_access_file, name='repo_access_file'),
(r'^repo/(?P<repo_id>[^/]+)/view/(?P<obj_id>[^/]+)/$', repo_view_file), (r'^repo/(?P<repo_id>[^/]+)/files/$', repo_view_file),
(r'^repo/(?P<repo_id>[^/]+)/file/get/$', repo_file_get),
(r'^download/repo/$', repo_download), (r'^download/repo/$', repo_download),
(r'^file/move/get_subdir/$', get_subdir), (r'^file/move/get_subdir/$', get_subdir),

View File

@@ -68,13 +68,13 @@ def get_ccnetapplet_root():
ccnet_applet_root = settings.CCNET_APPLET_ROOT ccnet_applet_root = settings.CCNET_APPLET_ROOT
return ccnet_applet_root return ccnet_applet_root
def gen_token(): def gen_token(max_length=5):
""" """
Generate short token used for owner to access repo file. Generate a random token.
""" """
token = sha_constructor(settings.SECRET_KEY + unicode(time.time())).hexdigest()[:5] token = sha_constructor(settings.SECRET_KEY + unicode(time.time())).hexdigest()[:max_length]
return token return token
def validate_group_name(group_name): def validate_group_name(group_name):

355
views.py
View File

@@ -24,6 +24,7 @@ from auth.decorators import login_required
from auth.forms import AuthenticationForm, PasswordResetForm, SetPasswordForm, \ from auth.forms import AuthenticationForm, PasswordResetForm, SetPasswordForm, \
PasswordChangeForm PasswordChangeForm
from auth.tokens import default_token_generator from auth.tokens import default_token_generator
from share.models import FileShare
from seaserv import ccnet_rpc, ccnet_threaded_rpc, get_groups, get_users, get_repos, \ from seaserv import ccnet_rpc, ccnet_threaded_rpc, get_groups, get_users, get_repos, \
get_repo, get_commits, get_branches, \ get_repo, get_commits, get_branches, \
seafserv_threaded_rpc, seafserv_rpc, get_binding_peerids, get_ccnetuser, \ seafserv_threaded_rpc, seafserv_rpc, get_binding_peerids, get_ccnetuser, \
@@ -33,7 +34,7 @@ from pysearpc import SearpcError
from seahub.base.accounts import CcnetUser from seahub.base.accounts import CcnetUser
from seahub.contacts.models import Contact from seahub.contacts.models import Contact
from seahub.notifications.models import UserNotification from seahub.notifications.models import UserNotification
from forms import AddUserForm from forms import AddUserForm, FileLinkShareForm
from utils import go_permission_error, go_error, list_to_string, \ from utils import go_permission_error, go_error, list_to_string, \
get_httpserver_root, get_ccnetapplet_root, gen_token, \ get_httpserver_root, get_ccnetapplet_root, gen_token, \
calculate_repo_last_modify, valid_previewed_file, \ calculate_repo_last_modify, valid_previewed_file, \
@@ -147,8 +148,9 @@ def gen_path_link(path, repo_name):
Generate navigate paths and links in repo page. Generate navigate paths and links in repo page.
""" """
if path[-1:] != '/': if path and path[-1] != '/':
path += '/' path += '/'
paths = [] paths = []
links = [] links = []
if path and path != '/': if path and path != '/':
@@ -210,7 +212,6 @@ def render_repo(request, repo_id, error=''):
# query repo infomation # query repo infomation
repo_size = seafserv_threaded_rpc.server_repo_size(repo_id) repo_size = seafserv_threaded_rpc.server_repo_size(repo_id)
# latest_commit = get_commits(repo_id, 0, 1)[0]
# get repo dirents # get repo dirents
dirs = [] dirs = []
@@ -789,24 +790,137 @@ def repo_del_file(request, repo_id):
url = reverse('repo', args=[repo_id]) + ('?p=%s' % parent_dir) url = reverse('repo', args=[repo_id]) + ('?p=%s' % parent_dir)
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
def repo_view_file(request, repo_id, obj_id): def repo_view_file(request, repo_id):
"""
Preview file on web, including files in current worktree and history.
"""
http_server_root = get_httpserver_root() http_server_root = get_httpserver_root()
filename = urllib2.quote(request.GET.get('file_name', '').encode('utf-8')) path = request.GET.get('p', '/')
if path[-1] != '/':
path = path + '/'
filename = urllib2.quote(os.path.basename(path[:-1]).encode('utf-8'))
commit_id = request.GET.get('commit_id', '') commit_id = request.GET.get('commit_id', '')
view_history = True if commit_id else False view_history = True if commit_id else False
current_commit = seafserv_threaded_rpc.get_commit(commit_id) current_commit = seafserv_threaded_rpc.get_commit(commit_id)
if not current_commit: if not current_commit:
current_commit = get_commits(repo_id, 0, 1)[0] current_commit = get_commits(repo_id, 0, 1)[0]
if request.is_ajax(): if view_history:
content_type = 'application/json; charset=utf-8' obj_id = request.GET.get('obj_id', '')
token = request.GET.get('t') else:
try:
obj_id = seafserv_rpc.get_file_by_path(repo_id, path[:-1])
except:
obj_id = None
if not obj_id:
return go_error(request, '文件不存在')
repo = get_repo(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
token = gen_token()
# put token into memory in seaf-server
seafserv_rpc.web_save_access_token(token, obj_id)
else:
raise Http404
# generate path and link
zipped = gen_path_link(path, repo.name)
# determin whether file can preview on web
can_preview, filetype = valid_previewed_file(filename)
# raw path
tmp_str = '%s/access?repo_id=%s&id=%s&filename=%s&op=%s&t=%s&u=%s' tmp_str = '%s/access?repo_id=%s&id=%s&filename=%s&op=%s&t=%s&u=%s'
redirect_url = tmp_str % (http_server_root, raw_path = tmp_str % (http_server_root,
repo_id, obj_id, repo_id, obj_id,
filename, 'view', filename, 'view',
token, token,
request.user.username) request.user.username)
# file share link
l = FileShare.objects.filter(repo_id=repo_id).filter(path=path[:-1])
fileshare = l[0] if len(l) > 0 else None
http_or_https = request.is_secure() and 'https' or 'http'
domain = RequestSite(request).domain
if fileshare:
file_shared_link = '%s://%s%sf/%s/' % (http_or_https, domain,
settings.SITE_ROOT,
fileshare.token)
else:
file_shared_link = ''
return render_to_response('repo_view_file.html', {
'repo': repo,
'path': path,
'obj_id': obj_id,
'file_name': filename,
'path': path,
'zipped': zipped,
'view_history': view_history,
'current_commit': current_commit,
'token': token,
'can_preview': can_preview,
'filetype': filetype,
'raw_path': raw_path,
'fileshare': fileshare,
'protocol': http_or_https,
'domain': domain,
'file_shared_link': file_shared_link,
}, context_instance=RequestContext(request))
def repo_file_get(request, repo_id):
"""
Handle ajax request to get file content from httpserver.
If get current worktree file, need access_token, path and username from
url params.
If get history file, need access_token, path username and obj_id from
url params.
"""
if not request.is_ajax():
return Http404
http_server_root = get_httpserver_root()
content_type = 'application/json; charset=utf-8'
access_token = request.GET.get('t')
path = request.GET.get('p', '/')
if path[-1] == '/':
path = path[:-1]
filename = urllib2.quote(os.path.basename(path).encode('utf-8'))
obj_id = request.GET.get('obj_id', '')
if not obj_id:
try:
obj_id = seafserv_rpc.get_file_by_path(repo_id, path)
except:
obj_id = None
if not obj_id:
data = json.dumps([{'error': '获取文件数据失败'}])
return HttpResponse(data, status=400, content_type=content_type)
username = request.GET.get('u', '')
tmp_str = '%s/access?repo_id=%s&id=%s&filename=%s&op=%s&t=%s&u=%s'
redirect_url = tmp_str % (http_server_root,
repo_id, obj_id,
filename, 'view',
access_token,
username)
try: try:
proxied_request = urllib2.urlopen(redirect_url) proxied_request = urllib2.urlopen(redirect_url)
if long(proxied_request.headers['Content-Length']) > FILE_PREVIEW_MAX_SIZE: if long(proxied_request.headers['Content-Length']) > FILE_PREVIEW_MAX_SIZE:
@@ -835,69 +949,6 @@ def repo_view_file(request, repo_id, obj_id):
data = json.dumps(l) data = json.dumps(l)
return HttpResponse(data, status=200, content_type=content_type) return HttpResponse(data, status=200, content_type=content_type)
repo = get_repo(repo_id)
if not repo:
raise Http404
# 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'
# 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 = ''
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:
# owner should get a token to visit repo
token = gen_token()
# put token into memory in seaf-server
seafserv_rpc.web_save_access_token(token, obj_id)
else:
raise Http404
# query commit info
commit_id = request.GET.get('commit_id', None)
current_commit = seafserv_threaded_rpc.get_commit(commit_id)
if not current_commit:
current_commit = get_commits(repo.id, 0, 1)[0]
# generate path and link
path = request.GET.get('p', '/')
zipped = gen_path_link(path, repo.name)
# filename
can_preview, filetype = valid_previewed_file(filename)
# raw path
tmp_str = '%s/access?repo_id=%s&id=%s&filename=%s&op=%s&t=%s&u=%s'
raw_path = tmp_str % (http_server_root,
repo_id, obj_id,
filename, 'view',
token,
request.user.username)
return render_to_response('repo_view_file.html', {
'repo': repo,
'path': path,
'obj_id': obj_id,
'file_name': filename,
'zipped': zipped,
'view_history': view_history,
'current_commit': current_commit,
'token': token,
'can_preview': can_preview,
'filetype': filetype,
'raw_path': raw_path,
}, context_instance=RequestContext(request))
def repo_access_file(request, repo_id, obj_id): def repo_access_file(request, repo_id, obj_id):
if repo_id: if repo_id:
repo = get_repo(repo_id) repo = get_repo(repo_id)
@@ -1756,3 +1807,163 @@ def file_revisions(request, repo_id):
% (commit_id, file_name, path) % (commit_id, file_name, path)
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
@login_required
def get_shared_link(request):
"""
Handle ajax request to generate file shared link.
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
repo_id = request.GET.get('repo_id')
obj_id = request.GET.get('obj_id')
path = request.GET.get('p', '/')
if path[-1] == '/':
path = path[:-1]
l = FileShare.objects.filter(repo_id=repo_id).filter(path=path)
if len(l) > 0:
fileshare = l[0]
token = fileshare.token
else:
token = gen_token(max_length=10)
fs = FileShare()
fs.username = request.user.username
fs.repo_id = repo_id
fs.path = path
fs.token = token
try:
fs.save()
except IntegrityError, e:
err = '获取分享链接失败,请重新获取'
data = json.dumps([{'error': err}])
return HttpResponse(data, status=500, content_type=content_type)
data = json.dumps([{'token': token}])
return HttpResponse(data, status=200, content_type=content_type)
def view_shared_file(request, token):
"""
Preview file via shared link.
"""
assert token is not None # Checked by URLconf
try:
fileshare = FileShare.objects.get(token=token)
except FileShare.DoesNotExist:
raise Http404
username = fileshare.username
repo_id = fileshare.repo_id
path = fileshare.path
http_server_root = get_httpserver_root()
if path[-1] == '/':
path = path[:-1]
filename = os.path.basename(path)
quote_filename = urllib2.quote(filename.encode('utf-8'))
try:
obj_id = seafserv_rpc.get_file_by_path(repo_id, path)
except:
obj_id = None
if not obj_id:
return go_error(request, '文件不存在')
repo = get_repo(repo_id)
if not repo:
raise Http404
access_token = gen_token()
seafserv_rpc.web_save_access_token(access_token, obj_id)
can_preview, filetype = valid_previewed_file(filename)
# raw path
tmp_str = '%s/access?repo_id=%s&id=%s&filename=%s&op=%s&t=%s&u=%s'
raw_path = tmp_str % (http_server_root,
repo_id, obj_id,
quote_filename, 'view',
access_token,
username)
return render_to_response('view_shared_file.html', {
'repo': repo,
'obj_id': obj_id,
'path': path,
'file_name': filename,
'token': token,
'access_token': access_token,
'can_preview': can_preview,
'filetype': filetype,
'raw_path': raw_path,
'username': username,
}, context_instance=RequestContext(request))
@login_required
def remove_shared_link(request):
"""
Handle ajax request to remove file shared link.
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
token = request.GET.get('t', '')
FileShare.objects.filter(token=token).delete()
msg = '删除成功'
data = json.dumps([{'msg': msg}])
return HttpResponse(data, status=200, content_type=content_type)
@login_required
def send_shared_link(request):
"""
Handle ajax post request to share file shared link.
"""
if not request.is_ajax() and not request.method == 'POST':
raise Http404
content_type = 'application/json; charset=utf-8'
form = FileLinkShareForm(request.POST)
if not form.is_valid():
err = '发送失败'
data = json.dumps([{'error':err}])
return HttpResponse(data, status=400, content_type=content_type)
email = form.cleaned_data['email']
file_shared_link = form.cleaned_data['file_shared_link']
# Handle the diffent separator
to_email_str = email.replace(';',',')
to_email_str = to_email_str.replace('\n',',')
to_email_str = to_email_str.replace('\r',',')
to_email_list = to_email_str.split(',')
t = loader.get_template('shared_link_email.html')
for to_email in to_email_list:
c = {
'email': request.user.username,
'to_email': to_email,
'file_shared_link': file_shared_link,
}
try:
send_mail('您的好友通过SeaCloud分享了一个文件给您',
t.render(Context(c)), None, [to_email],
fail_silently=False)
except:
err = '发送失败'
data = json.dumps([{'error':err}])
return HttpResponse(data, status=400, content_type=content_type)
msg = '发送成功。'
data = json.dumps([{'msg': msg}])
return HttpResponse(data, status=200, content_type=content_type)