diff --git a/seahub/api2/endpoints/send_share_link_email.py b/seahub/api2/endpoints/send_share_link_email.py new file mode 100644 index 0000000000..0f3f41f5b6 --- /dev/null +++ b/seahub/api2/endpoints/send_share_link_email.py @@ -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) diff --git a/seahub/api2/endpoints/send_upload_link_email.py b/seahub/api2/endpoints/send_upload_link_email.py new file mode 100644 index 0000000000..7c2c6e7316 --- /dev/null +++ b/seahub/api2/endpoints/send_upload_link_email.py @@ -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) + diff --git a/seahub/api2/urls.py b/seahub/api2/urls.py index 1bac546a37..8a0f059c8d 100644 --- a/seahub/api2/urls.py +++ b/seahub/api2/urls.py @@ -7,6 +7,8 @@ from .endpoints.dir_shared_items import DirSharedItemsEndpoint from .endpoints.account import Account from .endpoints.shared_upload_links import SharedUploadLinksView 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('', 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/(?P[-0-9-a-f]{36})/$', BeSharedReposView.as_view(), name='beshared-repos'), 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-upload-links/$', SharedUploadLinksView.as_view()), url(r'^shared-files/$', SharedFilesView.as_view()), diff --git a/tests/api/endpoints/test_send_share_link.py b/tests/api/endpoints/test_send_share_link.py new file mode 100644 index 0000000000..a76bc49e73 --- /dev/null +++ b/tests/api/endpoints/test_send_share_link.py @@ -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) diff --git a/tests/api/endpoints/test_send_upload_link.py b/tests/api/endpoints/test_send_upload_link.py new file mode 100644 index 0000000000..4bd41f88aa --- /dev/null +++ b/tests/api/endpoints/test_send_upload_link.py @@ -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)