mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-25 14:50:29 +00:00
Merge pull request #1047 from haiwen/email
[api2] add send share/upload link api
This commit is contained in:
113
seahub/api2/endpoints/send_share_link_email.py
Normal file
113
seahub/api2/endpoints/send_share_link_email.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from rest_framework.authentication import SessionAuthentication
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework.throttling import UserRateThrottle
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework import status
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
|
from seahub.api2.utils import api_error
|
||||||
|
|
||||||
|
from seahub.utils import IS_EMAIL_CONFIGURED, is_valid_username, \
|
||||||
|
string2list, gen_shared_link, send_html_email
|
||||||
|
from seahub.share.models import FileShare
|
||||||
|
|
||||||
|
from seahub.settings import REPLACE_FROM_EMAIL, ADD_REPLY_TO_HEADER, SITE_NAME
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class SendShareLinkView(APIView):
|
||||||
|
|
||||||
|
authentication_classes = (TokenAuthentication, SessionAuthentication )
|
||||||
|
permission_classes = (IsAuthenticated,)
|
||||||
|
throttle_classes = (UserRateThrottle, )
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
|
||||||
|
if not IS_EMAIL_CONFIGURED:
|
||||||
|
error_msg = _(u'Sending shared link failed. Email service is not properly configured, please contact administrator.')
|
||||||
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
|
# check args
|
||||||
|
email = request.POST.get('email', None)
|
||||||
|
if not email:
|
||||||
|
error_msg = 'email invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
token = request.POST.get('token', None)
|
||||||
|
if not token:
|
||||||
|
error_msg = 'token invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
extra_msg = request.POST.get('extra_msg', '')
|
||||||
|
|
||||||
|
# check if token exists
|
||||||
|
try:
|
||||||
|
link = FileShare.objects.get(token=token)
|
||||||
|
except FileShare.DoesNotExist:
|
||||||
|
error_msg = 'token %s not found.' % token
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
# check if is share link owner
|
||||||
|
username = request.user.username
|
||||||
|
if not link.is_owner(username):
|
||||||
|
error_msg = 'Permission denied.'
|
||||||
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
result['failed'] = []
|
||||||
|
result['success'] = []
|
||||||
|
to_email_list = string2list(email)
|
||||||
|
for to_email in to_email_list:
|
||||||
|
|
||||||
|
failed_info = {}
|
||||||
|
|
||||||
|
if not is_valid_username(to_email):
|
||||||
|
failed_info['email'] = to_email
|
||||||
|
failed_info['error_msg'] = 'email invalid.'
|
||||||
|
result['failed'].append(failed_info)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# prepare basic info
|
||||||
|
c = {
|
||||||
|
'email': username,
|
||||||
|
'to_email': to_email,
|
||||||
|
'extra_msg': extra_msg,
|
||||||
|
}
|
||||||
|
|
||||||
|
if REPLACE_FROM_EMAIL:
|
||||||
|
from_email = username
|
||||||
|
else:
|
||||||
|
from_email = None # use default from email
|
||||||
|
|
||||||
|
if ADD_REPLY_TO_HEADER:
|
||||||
|
reply_to = username
|
||||||
|
else:
|
||||||
|
reply_to = None
|
||||||
|
|
||||||
|
c['file_shared_link'] = gen_shared_link(token, link.s_type)
|
||||||
|
c['file_shared_name'] = os.path.basename(link.path.rstrip('/'))
|
||||||
|
template = 'shared_link_email.html'
|
||||||
|
|
||||||
|
if link.s_type == 'f':
|
||||||
|
c['file_shared_type'] = _(u"file")
|
||||||
|
title = _(u'A file is shared to you on %s') % SITE_NAME
|
||||||
|
else:
|
||||||
|
c['file_shared_type'] = _(u"directory")
|
||||||
|
title = _(u'A directory is shared to you on %s') % SITE_NAME
|
||||||
|
|
||||||
|
# send email
|
||||||
|
try:
|
||||||
|
send_html_email(title, template, c, from_email, [to_email], reply_to=reply_to)
|
||||||
|
result['success'].append(to_email)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
failed_info['email'] = to_email
|
||||||
|
failed_info['error_msg'] = 'Internal Server Error'
|
||||||
|
result['failed'].append(failed_info)
|
||||||
|
|
||||||
|
return Response(result)
|
105
seahub/api2/endpoints/send_upload_link_email.py
Normal file
105
seahub/api2/endpoints/send_upload_link_email.py
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from rest_framework.authentication import SessionAuthentication
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.throttling import UserRateThrottle
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework import status
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
|
from seahub.api2.utils import api_error
|
||||||
|
|
||||||
|
from seahub.utils import IS_EMAIL_CONFIGURED, is_valid_username, \
|
||||||
|
string2list, gen_shared_upload_link, send_html_email
|
||||||
|
from seahub.share.models import UploadLinkShare
|
||||||
|
|
||||||
|
from seahub.settings import REPLACE_FROM_EMAIL, ADD_REPLY_TO_HEADER, SITE_NAME
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class SendUploadLinkView(APIView):
|
||||||
|
|
||||||
|
authentication_classes = (TokenAuthentication, SessionAuthentication )
|
||||||
|
permission_classes = (IsAuthenticated,)
|
||||||
|
throttle_classes = (UserRateThrottle, )
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
|
||||||
|
if not IS_EMAIL_CONFIGURED:
|
||||||
|
error_msg = _(u'Sending shared link failed. Email service is not properly configured, please contact administrator.')
|
||||||
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
|
# check args
|
||||||
|
email = request.POST.get('email', None)
|
||||||
|
if not email:
|
||||||
|
error_msg = 'email invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
token = request.POST.get('token', None)
|
||||||
|
if not token:
|
||||||
|
error_msg = 'token invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
extra_msg = request.POST.get('extra_msg', '')
|
||||||
|
|
||||||
|
# check if token exists
|
||||||
|
try:
|
||||||
|
link = UploadLinkShare.objects.get(token=token)
|
||||||
|
except UploadLinkShare.DoesNotExist:
|
||||||
|
error_msg = 'token %s not found.' % token
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
# check if is upload link owner
|
||||||
|
username = request.user.username
|
||||||
|
if not link.is_owner(username):
|
||||||
|
error_msg = 'Permission denied.'
|
||||||
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
result['failed'] = []
|
||||||
|
result['success'] = []
|
||||||
|
to_email_list = string2list(email)
|
||||||
|
for to_email in to_email_list:
|
||||||
|
|
||||||
|
failed_info = {}
|
||||||
|
if not is_valid_username(to_email):
|
||||||
|
failed_info['email'] = to_email
|
||||||
|
failed_info['error_msg'] = 'email invalid.'
|
||||||
|
result['failed'].append(failed_info)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# prepare basic info
|
||||||
|
c = {
|
||||||
|
'email': username,
|
||||||
|
'to_email': to_email,
|
||||||
|
'extra_msg': extra_msg,
|
||||||
|
}
|
||||||
|
|
||||||
|
if REPLACE_FROM_EMAIL:
|
||||||
|
from_email = username
|
||||||
|
else:
|
||||||
|
from_email = None # use default from email
|
||||||
|
|
||||||
|
if ADD_REPLY_TO_HEADER:
|
||||||
|
reply_to = username
|
||||||
|
else:
|
||||||
|
reply_to = None
|
||||||
|
|
||||||
|
c['shared_upload_link'] = gen_shared_upload_link(token)
|
||||||
|
title = _(u'An upload link is shared to you on %s') % SITE_NAME
|
||||||
|
template = 'shared_upload_link_email.html'
|
||||||
|
|
||||||
|
# send email
|
||||||
|
try:
|
||||||
|
send_html_email(title, template, c, from_email, [to_email], reply_to=reply_to)
|
||||||
|
result['success'].append(to_email)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
failed_info['email'] = to_email
|
||||||
|
failed_info['error_msg'] = 'Internal Server Error'
|
||||||
|
result['failed'].append(failed_info)
|
||||||
|
|
||||||
|
return Response(result)
|
||||||
|
|
@@ -7,6 +7,8 @@ from .endpoints.dir_shared_items import DirSharedItemsEndpoint
|
|||||||
from .endpoints.account import Account
|
from .endpoints.account import Account
|
||||||
from .endpoints.shared_upload_links import SharedUploadLinksView
|
from .endpoints.shared_upload_links import SharedUploadLinksView
|
||||||
from .endpoints.be_shared_repo import BeSharedReposView
|
from .endpoints.be_shared_repo import BeSharedReposView
|
||||||
|
from .endpoints.send_share_link_email import SendShareLinkView
|
||||||
|
from .endpoints.send_upload_link_email import SendUploadLinkView
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
url(r'^ping/$', Ping.as_view()),
|
url(r'^ping/$', Ping.as_view()),
|
||||||
@@ -53,6 +55,8 @@ urlpatterns = patterns('',
|
|||||||
url(r'^beshared-repos/$', BeShared.as_view(), name='beshared'),
|
url(r'^beshared-repos/$', BeShared.as_view(), name='beshared'),
|
||||||
url(r'^beshared-repos/(?P<repo_id>[-0-9-a-f]{36})/$', BeSharedReposView.as_view(), name='beshared-repos'),
|
url(r'^beshared-repos/(?P<repo_id>[-0-9-a-f]{36})/$', BeSharedReposView.as_view(), name='beshared-repos'),
|
||||||
url(r'^default-repo/$', DefaultRepoView.as_view(), name='api2-defaultrepo'),
|
url(r'^default-repo/$', DefaultRepoView.as_view(), name='api2-defaultrepo'),
|
||||||
|
url(r'^send-share-link/$', SendShareLinkView.as_view(), name='api2-send-share-link'),
|
||||||
|
url(r'^send-upload-link/$', SendUploadLinkView.as_view(), name='api2-send-upload-link'),
|
||||||
url(r'^shared-links/$', SharedLinksView.as_view()),
|
url(r'^shared-links/$', SharedLinksView.as_view()),
|
||||||
url(r'^shared-upload-links/$', SharedUploadLinksView.as_view()),
|
url(r'^shared-upload-links/$', SharedUploadLinksView.as_view()),
|
||||||
url(r'^shared-files/$', SharedFilesView.as_view()),
|
url(r'^shared-files/$', SharedFilesView.as_view()),
|
||||||
|
47
tests/api/endpoints/test_send_share_link.py
Normal file
47
tests/api/endpoints/test_send_share_link.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#coding: UTF-8
|
||||||
|
import json
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from seahub.utils import IS_EMAIL_CONFIGURED
|
||||||
|
from seahub.share.models import FileShare
|
||||||
|
from seahub.test_utils import BaseTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class SendShareLinkApiTest(BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
fs = FileShare.objects.create_file_link(self.user.username,
|
||||||
|
self.repo.id, self.file, None)
|
||||||
|
|
||||||
|
self.token = fs.token
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.remove_repo()
|
||||||
|
|
||||||
|
def test_can_send_email(self):
|
||||||
|
self.login_as(self.user)
|
||||||
|
invalid_email = 'invalid'
|
||||||
|
url = reverse("api2-send-share-link")
|
||||||
|
data = {
|
||||||
|
"token": self.token,
|
||||||
|
"email": self.admin.email + ',' + invalid_email,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.client.post(url, data)
|
||||||
|
if not IS_EMAIL_CONFIGURED:
|
||||||
|
self.assertEqual(403, resp.status_code)
|
||||||
|
else:
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
json_resp = json.loads(resp.content)
|
||||||
|
assert json_resp['success'][0] == self.admin.email
|
||||||
|
assert json_resp['failed'][0]['email'] == invalid_email
|
||||||
|
|
||||||
|
def test_can_not_send_email_if_not_link_owner(self):
|
||||||
|
self.login_as(self.admin)
|
||||||
|
url = reverse("api2-send-share-link")
|
||||||
|
data = {
|
||||||
|
"token": self.token,
|
||||||
|
"email": self.admin.email,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.client.post(url, data)
|
||||||
|
self.assertEqual(403, resp.status_code)
|
46
tests/api/endpoints/test_send_upload_link.py
Normal file
46
tests/api/endpoints/test_send_upload_link.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#coding: UTF-8
|
||||||
|
import json
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from seahub.utils import IS_EMAIL_CONFIGURED
|
||||||
|
from seahub.test_utils import BaseTestCase
|
||||||
|
from seahub.share.models import UploadLinkShare
|
||||||
|
|
||||||
|
|
||||||
|
class SendUploadLinkApiTest(BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
uls = UploadLinkShare.objects.create_upload_link_share(self.user.username,
|
||||||
|
self.repo.id, '/')
|
||||||
|
self.token = uls.token
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.remove_repo()
|
||||||
|
|
||||||
|
def test_can_send_email(self):
|
||||||
|
self.login_as(self.user)
|
||||||
|
invalid_email = 'invalid'
|
||||||
|
url = reverse("api2-send-upload-link")
|
||||||
|
data = {
|
||||||
|
"token": self.token,
|
||||||
|
"email": self.admin.email + ',' + invalid_email,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.client.post(url, data)
|
||||||
|
if not IS_EMAIL_CONFIGURED:
|
||||||
|
self.assertEqual(403, resp.status_code)
|
||||||
|
else:
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
json_resp = json.loads(resp.content)
|
||||||
|
assert json_resp['success'][0] == self.admin.email
|
||||||
|
assert json_resp['failed'][0]['email'] == invalid_email
|
||||||
|
|
||||||
|
def test_can_not_send_email_if_not_link_owner(self):
|
||||||
|
self.login_as(self.admin)
|
||||||
|
url = reverse("api2-send-upload-link")
|
||||||
|
data = {
|
||||||
|
"token": self.token,
|
||||||
|
"email": self.admin.email,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.client.post(url, data)
|
||||||
|
self.assertEqual(403, resp.status_code)
|
Reference in New Issue
Block a user