From aee169b3f21b153d3672857a78a5a9369623d3b9 Mon Sep 17 00:00:00 2001 From: lian Date: Mon, 27 Sep 2021 17:44:23 +0800 Subject: [PATCH] receive share from other service --- frontend/src/app.js | 3 + frontend/src/components/main-side-nav.js | 10 +- .../pages/ocm-via-webdav/ocm-via-webdav.js | 184 +++++++++ frontend/src/utils/constants.js | 1 + seahub/ocm_via_webdav/__init__.py | 0 .../ocm_via_webdav/migrations/0001_initial.py | 38 ++ .../migrations/0002_auto_20210926_1503.py | 17 + .../migrations/0003_auto_20210926_1505.py | 32 ++ seahub/ocm_via_webdav/migrations/__init__.py | 0 seahub/ocm_via_webdav/models.py | 25 ++ seahub/ocm_via_webdav/ocm_api.py | 373 ++++++++++++++++++ seahub/ocm_via_webdav/settings.py | 4 + seahub/ocm_via_webdav/urls.py | 17 + seahub/settings.py | 2 +- seahub/templates/base_for_react.html | 1 + seahub/urls.py | 5 +- seahub/views/__init__.py | 2 + 17 files changed, 711 insertions(+), 3 deletions(-) create mode 100644 frontend/src/pages/ocm-via-webdav/ocm-via-webdav.js create mode 100644 seahub/ocm_via_webdav/__init__.py create mode 100644 seahub/ocm_via_webdav/migrations/0001_initial.py create mode 100644 seahub/ocm_via_webdav/migrations/0002_auto_20210926_1503.py create mode 100644 seahub/ocm_via_webdav/migrations/0003_auto_20210926_1505.py create mode 100644 seahub/ocm_via_webdav/migrations/__init__.py create mode 100644 seahub/ocm_via_webdav/models.py create mode 100644 seahub/ocm_via_webdav/ocm_api.py create mode 100644 seahub/ocm_via_webdav/settings.py create mode 100644 seahub/ocm_via_webdav/urls.py diff --git a/frontend/src/app.js b/frontend/src/app.js index 37b51e0e60..90d4db6f9e 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -20,6 +20,7 @@ import ShareAdminShareLinks from './pages/share-admin/share-links'; import ShareAdminUploadLinks from './pages/share-admin/upload-links'; import SharedLibraries from './pages/shared-libs/shared-libs'; import ShareWithOCM from './pages/share-with-ocm/shared-with-ocm'; +import OCMViaWebdav from './pages/ocm-via-webdav/ocm-via-webdav'; import OCMRepoDir from './pages/share-with-ocm/remote-dir-view'; import MyLibraries from './pages/my-libs/my-libs'; import MyLibDeleted from './pages/my-libs/my-libs-deleted'; @@ -41,6 +42,7 @@ const StarredWrapper = MainContentWrapper(Starred); const LinkedDevicesWrapper = MainContentWrapper(LinkedDevices); const SharedLibrariesWrapper = MainContentWrapper(SharedLibraries); const SharedWithOCMWrapper = MainContentWrapper(ShareWithOCM); +const OCMViaWebdavWrapper = MainContentWrapper(OCMViaWebdav); const ShareAdminLibrariesWrapper = MainContentWrapper(ShareAdminLibraries); const ShareAdminFoldersWrapper = MainContentWrapper(ShareAdminFolders); const ShareAdminShareLinksWrapper = MainContentWrapper(ShareAdminShareLinks); @@ -261,6 +263,7 @@ class App extends Component { + diff --git a/frontend/src/components/main-side-nav.js b/frontend/src/components/main-side-nav.js index 84f2029220..25db3fd82e 100644 --- a/frontend/src/components/main-side-nav.js +++ b/frontend/src/components/main-side-nav.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Link } from '@reach/router'; import { Badge } from 'reactstrap'; -import { gettext, siteRoot, canPublishRepo, canAddRepo, canGenerateShareLink, canGenerateUploadLink, canInvitePeople, dtableWebServer, enableOCM } from '../utils/constants'; +import { gettext, siteRoot, canPublishRepo, canAddRepo, canGenerateShareLink, canGenerateUploadLink, canInvitePeople, dtableWebServer, enableOCM, enableOCMViaWebdav } from '../utils/constants'; import { seafileAPI } from '../utils/seafile-api'; import { Utils } from '../utils/utils'; import toaster from './toast'; @@ -224,6 +224,14 @@ class MainSideNav extends React.Component { } + {enableOCMViaWebdav && +
  • + this.tabItemClick(e, 'ocm-via-webdav')}> + + {gettext('Shared from other servers')} + +
  • + } diff --git a/frontend/src/pages/ocm-via-webdav/ocm-via-webdav.js b/frontend/src/pages/ocm-via-webdav/ocm-via-webdav.js new file mode 100644 index 0000000000..cbce63f36e --- /dev/null +++ b/frontend/src/pages/ocm-via-webdav/ocm-via-webdav.js @@ -0,0 +1,184 @@ +import React, { Component, Fragment } from 'react'; +import PropTypes from 'prop-types'; +import moment from 'moment'; +import { Link } from '@reach/router'; +import { gettext, siteRoot } from '../../utils/constants'; +import { seafileAPI } from '../../utils/seafile-api'; +import { Utils } from '../../utils/utils'; +import toaster from '../../components/toast'; +import Loading from '../../components/loading'; +import EmptyTip from '../../components/empty-tip'; + +class Content extends Component { + + render() { + const { loading, errorMsg, items } = this.props; + + const emptyTip = ( + +

    {gettext('No libraries have been shared with you')}

    +

    {gettext('No libraries have been shared with you from other servers.')}

    +
    + ); + + if (loading) { + return ; + } else if (errorMsg) { + return

    {errorMsg}

    ; + } else { + const table = ( + + + + + + + + + + + + + {items.map((item, index) => { + return ; + })} + +
    {gettext('Name')}{gettext('Shared by')}{gettext('Time')}{/* operations */}{/* operations */}
    + ); + + return items.length ? table : emptyTip; + } + } +} + +Content.propTypes = { + loading: PropTypes.bool.isRequired, + errorMsg: PropTypes.string.isRequired, + items: PropTypes.array.isRequired, +}; + +class Item extends Component { + + constructor(props) { + super(props); + this.state = { + isOpIconShown: false + }; + } + + handleMouseOver = () => { + this.setState({ + isOpIconShown: true + }); + } + + handleMouseOut = () => { + this.setState({ + isOpIconShown: false + }); + } + + downloadFile = () => { + let downloadUrl = siteRoot + 'ocm-via-webdav/download-received-file/?share_id=' + this.props.item.id; + window.location.href = downloadUrl; + } + + leaveShare = (e) => { + e.preventDefault(); + this.props.leaveShare(this.props.item); + } + + render() { + const item = this.props.item; + const { isOpIconShown } = this.state; + + item.icon_url = Utils.getFileIconUrl(item.name); + return ( + + + + {item.name} + + {item.shared_by} + {moment(item.ctime).fromNow()} + + + + + + + + ); + } +} + +Item.propTypes = { + item: PropTypes.object.isRequired +}; + +class OCMViaWebdav extends Component { + constructor(props) { + super(props); + this.state = { + loading: true, + errorMsg: '', + items: [] + }; + } + + componentDidMount() { + const url = seafileAPI.server + '/ocm-via-webdav/received-shares/'; + seafileAPI.req.get(url).then((res) => { + this.setState({ + loading: false, + items: res.data.received_share_list + }); + }).catch(error => { + let errMessage = Utils.getErrorMsg(error); + toaster.danger(errMessage); + }); + } + + leaveShare = (item) => { + const { id, name } = item; + const url = seafileAPI.server + '/ocm-via-webdav/received-shares/' + id + '/'; + seafileAPI.req.delete(url).then((res) => { + let items = this.state.items.filter(item => { + return item.id != id; + }); + this.setState({items: items}); + toaster.success(gettext('Successfully unshared {name}').replace('{name}', name)); + }).catch(error => { + let errMessage = Utils.getErrorMsg(error); + toaster.danger(errMessage); + }); + } + + render() { + return ( + +
    +
    +
    +

    {gettext('Shared from other servers')}

    +
    +
    + +
    +
    +
    +
    + ); + } +} + +export default OCMViaWebdav; diff --git a/frontend/src/utils/constants.js b/frontend/src/utils/constants.js index 7353861a67..7aa092940a 100644 --- a/frontend/src/utils/constants.js +++ b/frontend/src/utils/constants.js @@ -74,6 +74,7 @@ export const maxUploadFileSize = window.app.pageOptions.maxUploadFileSize; export const maxNumberOfFilesForFileupload = window.app.pageOptions.maxNumberOfFilesForFileupload; export const enableOCM = window.app.pageOptions.enableOCM; export const ocmRemoteServers = window.app.pageOptions.ocmRemoteServers; +export const enableOCMViaWebdav = window.app.pageOptions.enableOCMViaWebdav; export const curNoteMsg = window.app.pageOptions.curNoteMsg; export const curNoteID = window.app.pageOptions.curNoteID; diff --git a/seahub/ocm_via_webdav/__init__.py b/seahub/ocm_via_webdav/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/seahub/ocm_via_webdav/migrations/0001_initial.py b/seahub/ocm_via_webdav/migrations/0001_initial.py new file mode 100644 index 0000000000..0b9b052043 --- /dev/null +++ b/seahub/ocm_via_webdav/migrations/0001_initial.py @@ -0,0 +1,38 @@ +# Generated by Django 2.2.14 on 2021-09-16 16:55 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='ShareReceived', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.CharField(blank=True, max_length=255, null=True)), + ('name', models.CharField(db_index=True, max_length=255)), + ('owner', models.CharField(db_index=True, max_length=255)), + ('owner_display_name', models.CharField(blank=True, max_length=255, null=True)), + ('protocol_name', models.CharField(db_index=True, max_length=255)), + ('shared_secret', models.CharField(db_index=True, max_length=255)), + ('permissions', models.CharField(db_index=True, max_length=255)), + ('provider_id', models.CharField(db_index=True, max_length=255)), + ('resource_type', models.CharField(db_index=True, max_length=255)), + ('share_type', models.CharField(db_index=True, max_length=255)), + ('share_with', models.CharField(db_index=True, max_length=255)), + ('shared_by', models.CharField(db_index=True, max_length=255)), + ('shared_by_display_name', models.CharField(blank=True, max_length=255, null=True)), + ('ctime', models.DateTimeField(default=django.utils.timezone.now)), + ], + options={ + 'db_table': 'ocm_via_webdav_share_received', + }, + ), + ] diff --git a/seahub/ocm_via_webdav/migrations/0002_auto_20210926_1503.py b/seahub/ocm_via_webdav/migrations/0002_auto_20210926_1503.py new file mode 100644 index 0000000000..6b50023dfe --- /dev/null +++ b/seahub/ocm_via_webdav/migrations/0002_auto_20210926_1503.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.14 on 2021-09-26 15:03 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ocm_via_webdav', '0001_initial'), + ] + + operations = [ + migrations.RenameModel( + old_name='ShareReceived', + new_name='ReceivedShares', + ), + ] diff --git a/seahub/ocm_via_webdav/migrations/0003_auto_20210926_1505.py b/seahub/ocm_via_webdav/migrations/0003_auto_20210926_1505.py new file mode 100644 index 0000000000..71fa8e080a --- /dev/null +++ b/seahub/ocm_via_webdav/migrations/0003_auto_20210926_1505.py @@ -0,0 +1,32 @@ +# Generated by Django 2.2.14 on 2021-09-26 15:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ocm_via_webdav', '0002_auto_20210926_1503'), + ] + + operations = [ + migrations.AlterField( + model_name='receivedshares', + name='name', + field=models.CharField(max_length=255), + ), + migrations.AlterField( + model_name='receivedshares', + name='permissions', + field=models.CharField(max_length=255), + ), + migrations.AlterField( + model_name='receivedshares', + name='protocol_name', + field=models.CharField(max_length=255), + ), + migrations.AlterModelTable( + name='receivedshares', + table='ocm_via_webdav_received_shares', + ), + ] diff --git a/seahub/ocm_via_webdav/migrations/__init__.py b/seahub/ocm_via_webdav/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/seahub/ocm_via_webdav/models.py b/seahub/ocm_via_webdav/models.py new file mode 100644 index 0000000000..4fbbf9b53b --- /dev/null +++ b/seahub/ocm_via_webdav/models.py @@ -0,0 +1,25 @@ +from django.db import models +from django.utils import timezone + + +class ReceivedShares(models.Model): + + # https://cs3org.github.io/OCM-API/docs.html + + class Meta: + db_table = 'ocm_via_webdav_received_shares' + + description = models.CharField(max_length=255, blank=True, null=True) + name = models.CharField(max_length=255) + owner = models.CharField(max_length=255, db_index=True) + owner_display_name = models.CharField(max_length=255, blank=True, null=True) + protocol_name = models.CharField(max_length=255) + shared_secret = models.CharField(max_length=255, db_index=True) + permissions = models.CharField(max_length=255) + provider_id = models.CharField(max_length=255, db_index=True) + resource_type = models.CharField(max_length=255, db_index=True) + share_type = models.CharField(max_length=255, db_index=True) + share_with = models.CharField(max_length=255, db_index=True) + shared_by = models.CharField(max_length=255, db_index=True) + shared_by_display_name = models.CharField(max_length=255, blank=True, null=True) + ctime = models.DateTimeField(default=timezone.now) diff --git a/seahub/ocm_via_webdav/ocm_api.py b/seahub/ocm_via_webdav/ocm_api.py new file mode 100644 index 0000000000..e691c87348 --- /dev/null +++ b/seahub/ocm_via_webdav/ocm_api.py @@ -0,0 +1,373 @@ +import base64 +import logging +import requests +from constance import config + +from django.http import HttpResponse + +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView + +from seahub.api2.throttling import UserRateThrottle +from seahub.api2.utils import api_error + +from seahub.base.templatetags.seahub_tags import email2nickname + +from seahub.ocm_via_webdav.settings import ENABLE_OCM_VIA_WEBDAV, OCM_VIA_WEBDAV_ENDPOINT +from seahub.ocm_via_webdav.models import ReceivedShares + +from seahub.ocm.settings import ENABLE_OCM, OCM_SEAFILE_PROTOCOL, \ + OCM_RESOURCE_TYPE_LIBRARY, OCM_API_VERSION, OCM_SHARE_TYPES, \ + OCM_ENDPOINT + +logger = logging.getLogger(__name__) + + +class OCMProviderView(APIView): + + throttle_classes = (UserRateThrottle,) + + def get(self, request): + """ + Return ocm protocol info to remote server + """ + + result = {} + + if ENABLE_OCM: + + result = { + 'enabled': True, + 'apiVersion': OCM_API_VERSION, + 'endPoint': config.SERVICE_URL + '/' + OCM_ENDPOINT, + 'resourceTypes': { + 'name': OCM_RESOURCE_TYPE_LIBRARY, + 'shareTypes': OCM_SHARE_TYPES, + 'protocols': { + OCM_SEAFILE_PROTOCOL: OCM_SEAFILE_PROTOCOL, + } + } + } + + if ENABLE_OCM_VIA_WEBDAV: + + result = { + 'apiVersion': '1.0-proposal1', + 'enabled': True, + 'endPoint': config.SERVICE_URL + '/' + OCM_VIA_WEBDAV_ENDPOINT, + 'resourceTypes': { + 'name': 'file', + 'protocols': {'webdav': 'TODO'}, + 'shareTypes': ['user'], + } + } + return Response(result) + + +class SharesView(APIView): + + throttle_classes = (UserRateThrottle,) + + def post(self, request): + """ + Receive share from other service + """ + + if not ENABLE_OCM_VIA_WEBDAV: + error_msg = 'OCM via webdav feature is not enabled.' + return api_error(501, error_msg) + + # {'description': '', + # 'name': 'file-3-in-nextcloud-folder.md', + # 'owner': 'lian@https://nextcloud.seafile.top/', + # 'ownerDisplayName': 'lian', + # 'protocol': {'name': 'webdav', + # 'options': {'permissions': '{http://open-cloud-mesh.org/ns}share-permissions', + # 'sharedSecret': 'HdjKpI4o6lamWwN'}}, + # 'providerId': 9, + # 'resourceType': 'file', + # 'shareType': 'user', + # 'shareWith': 'lian@lian.com@https://demo.seafile.top', # or 'lian@https://demo.seafile.top', + # 'sharedBy': 'lian@https://nextcloud.seafile.top/', + # 'sharedByDisplayName': 'lian'} + + protocol_dict = request.data.get('protocol', {}) + protocol_name = protocol_dict.get('name') + shared_secret = protocol_dict.get('options').get('sharedSecret') + permissions = protocol_dict.get('options').get('permissions') + + owner = request.data.get('owner') + owner_display_name = request.data.get('owner_display_name') + + name = request.data.get('name') + description = request.data.get('description') + provider_id = request.data.get('providerId') + resource_type = request.data.get('resourceType') + share_type = request.data.get('shareType') + share_with = request.data.get('shareWith').split('http')[0].rstrip('@') + shared_by = request.data.get('sharedBy') + shared_by_display_name = request.data.get('sharedByDisplayName') + + share = ReceivedShares(description=description, + name=name, + owner=owner, + owner_display_name=owner_display_name, + protocol_name=protocol_name, + shared_secret=shared_secret, + permissions=permissions, + provider_id=provider_id, + resource_type=resource_type, + share_type=share_type, + share_with=share_with, + shared_by=shared_by, + shared_by_display_name=shared_by_display_name) + share.save() + + result = { + "recipientDisplayName": email2nickname(share_with) + } + return Response(result, status=status.HTTP_201_CREATED) + + +class ReceivedSharesView(APIView): + + throttle_classes = (UserRateThrottle,) + + def get(self, request): + """ + Get items shared from other service. + """ + + if not ENABLE_OCM_VIA_WEBDAV: + error_msg = 'OCM via webdav feature is not enabled.' + return api_error(501, error_msg) + + username = request.user.username + + info_list = [] + for share in ReceivedShares.objects.filter(share_with=username): + + info = {} + info['id'] = share.id + info['name'] = share.name + info['ctime'] = share.ctime + info['shared_by'] = share.shared_by + + info_list.append(info) + + result = { + 'received_share_list': info_list + } + return Response(result) + + +class ReceivedShareView(APIView): + + throttle_classes = (UserRateThrottle,) + + def delete(self, request, share_id): + """ + Delete item shared from other service. + """ + + if not ENABLE_OCM_VIA_WEBDAV: + error_msg = 'OCM via webdav feature is not enabled.' + return api_error(501, error_msg) + + try: + share = ReceivedShares.objects.get(id=share_id) + except ReceivedShares.DoesNotExist: + error_msg = "OCM share {} not found.".format(share_id) + return api_error(404, error_msg) + + username = request.user.username + if share.share_with != username: + error_msg = 'Permission denied.' + return api_error(403, error_msg) + + # get remote server endpoint + shared_by = share.shared_by + remote_domain = shared_by.split('@')[-1] + remote_domain = remote_domain.rstrip('/') + + ocm_provider_url = remote_domain + '/ocm-provider/' + resp = requests.get(ocm_provider_url) + end_point = resp.json().get('endPoint') + + if not end_point: + logger.error('Can not get endPoint from {}'.format(ocm_provider_url)) + logger.error(resp.content) + + end_point = end_point.rstrip('/') + + # send SHARE_DECLINED notification + data = { + "notification": { + "message": "Recipient declined the share", + "sharedSecret": "" + }, + "notificationType": "SHARE_DECLINED", + "providerId": "", + "resourceType": "" + } + + data['notification']['sharedSecret'] = share.shared_secret + data['providerId'] = share.provider_id + data['resourceType'] = share.resource_type + + notifications_url = end_point + '/notifications' + resp = requests.post(notifications_url, json=data) + if resp.status_code != 201: + logger.error('Error occurred when send notification to {}'.format(notifications_url)) + logger.error(resp.content) + + share.delete() + + result = { + 'success': True + } + return Response(result) + + +class DownloadReceivedFileView(APIView): + + throttle_classes = (UserRateThrottle,) + + def get(self, request): + """ + Download received file. + """ + + if not ENABLE_OCM_VIA_WEBDAV: + error_msg = 'OCM via webdav feature is not enabled.' + return api_error(501, error_msg) + + share_id = request.GET.get('share_id') + if not share_id: + error_msg = 'share_id invalid.' + return api_error(400, error_msg) + + try: + share_id = int(share_id) + except ValueError as e: + logger.error(e) + error_msg = 'share_id invalid.' + return api_error(400, error_msg) + + try: + share = ReceivedShares.objects.get(id=share_id) + except ReceivedShares.DoesNotExist: + error_msg = "OCM share {} not found.".format(share_id) + return api_error(404, error_msg) + + # get remote server endpoint + shared_by = share.shared_by + remote_domain = shared_by.split('@')[-1] + remote_domain = remote_domain.rstrip('/') + + ocm_provider_url = remote_domain + '/ocm-provider/' + resp = requests.get(ocm_provider_url) + + # { + # 'apiVersion': '1.0-proposal1', + # 'enabled': True, + # 'endPoint': 'https://nextcloud.seafile.top/index.php/ocm', + # 'resourceTypes': [ + # { + # 'name': 'file', + # 'protocols': {'webdav': '/public.php/webdav/'}, + # 'shareTypes': ['user', 'group'] + # } + # ] + # } + + resource_types = resp.json().get('resourceTypes', []) + if not resource_types: + logger.error('Can not get resource_types from {}'.format(ocm_provider_url)) + logger.error(resp.content) + error_msg = 'Internal Server Error' + return api_error(501, error_msg) + + protocols = resource_types[0].get('protocols') + if not protocols: + logger.error('Can not get protocols from {}'.format(ocm_provider_url)) + logger.error(resp.content) + error_msg = 'Internal Server Error' + return api_error(501, error_msg) + + webdav_url = protocols.get('webdav') + if not webdav_url: + logger.error('Can not get webdav url from {}'.format(ocm_provider_url)) + logger.error(resp.content) + error_msg = 'Internal Server Error' + return api_error(501, error_msg) + + # download file via webdav + full_webdav_url = remote_domain + webdav_url + + def format_string(string): + return string + (4 - len(string) % 4) * ':' + + shared_secret = share.shared_secret + token = base64.b64encode('{}'.format(format_string(shared_secret)).encode('utf-8')) + headers = {"Authorization": "Basic {}".format(token.decode('utf-8'))} + download_file_resp = requests.get(full_webdav_url, headers=headers) + + response = HttpResponse(download_file_resp.content, content_type="application/octet-stream") + response['Content-Disposition'] = 'attachment; filename={}'.format(share.name) + + return response + + +class NotificationsView(APIView): + + throttle_classes = (UserRateThrottle,) + + def post(self, request): + """ + Receive notification from remote server. + """ + + if not ENABLE_OCM_VIA_WEBDAV: + error_msg = 'OCM via webdav feature is not enabled.' + return api_error(501, error_msg) + + # {'notification': {'messgage': 'file is no longer shared with you', + # 'sharedSecret': 'QoVQuBhqphvVYvz'}, + # 'notificationType': 'SHARE_UNSHARED', + # 'providerId': '13', + # 'resourceType': 'file'} + + notification_type = request.data.get('notificationType') + notification_dict = request.data.get('notification') + shared_secret = notification_dict.get('sharedSecret') + provider_id = notification_dict.get('providerId') + + error_result_not_found = { + "message": "RESOURCE_NOT_FOUND", + "validationErrors": [ + { + "name": "", + "message": "NOT_FOUND" + } + ] + } + + if notification_type == 'SHARE_UNSHARED': + + try: + share = ReceivedShares.objects.get(shared_secret=shared_secret) + except ReceivedShares.DoesNotExist: + error_msg = "OCM share with secret {} not found.".format(shared_secret) + error_result_not_found['validationErrors']['name'] = 'sharedSecret' + return Response(error_result_not_found, status=400) + + if share.provider_id != provider_id: + error_msg = "OCM share with provider id {} not found.".format(provider_id) + error_result_not_found['validationErrors']['name'] = 'providerID' + return Response(error_result_not_found, status=400) + + share.delete() + + return Response({}, status=status.HTTP_201_CREATED) diff --git a/seahub/ocm_via_webdav/settings.py b/seahub/ocm_via_webdav/settings.py new file mode 100644 index 0000000000..3aac1ee280 --- /dev/null +++ b/seahub/ocm_via_webdav/settings.py @@ -0,0 +1,4 @@ +from django.conf import settings + +ENABLE_OCM_VIA_WEBDAV = getattr(settings, 'ENABLE_OCM_VIA_WEBDAV', False) +OCM_VIA_WEBDAV_ENDPOINT = getattr(settings, 'OCM_VIA_WEBDAV_ENDPOINT', 'ocm-via-webdav') diff --git a/seahub/ocm_via_webdav/urls.py b/seahub/ocm_via_webdav/urls.py new file mode 100644 index 0000000000..3ce6ad08b6 --- /dev/null +++ b/seahub/ocm_via_webdav/urls.py @@ -0,0 +1,17 @@ +from django.urls import path + +from seahub.views import react_fake_view +from seahub.ocm_via_webdav.ocm_api import SharesView, ReceivedSharesView, \ + ReceivedShareView, DownloadReceivedFileView, NotificationsView + +urlpatterns = [ + + path(r'', react_fake_view, name="ocm_via_webdav"), + + path('shares', SharesView.as_view(), name='ocm-via-webdav-shares'), + path('notifications', NotificationsView.as_view(), name='ocm-via-webdav-notifications'), + + path('received-shares/', ReceivedSharesView.as_view(), name='ocm-via-webdav-received-shares'), + path('received-shares//', ReceivedShareView.as_view(), name='ocm-via-webdav-received-share'), + path('download-received-file/', DownloadReceivedFileView.as_view(), name='ocm-via-webdav-download-received-file'), +] diff --git a/seahub/settings.py b/seahub/settings.py index cf975aa011..27dabaa25b 100644 --- a/seahub/settings.py +++ b/seahub/settings.py @@ -263,7 +263,7 @@ INSTALLED_APPS = [ 'seahub.abuse_reports', 'seahub.repo_auto_delete', 'seahub.ocm', - + 'seahub.ocm_via_webdav', 'seahub.search', 'seahub.sysadmin_extra', 'seahub.organizations', diff --git a/seahub/templates/base_for_react.html b/seahub/templates/base_for_react.html index d78fc2e0f5..b2a3404a99 100644 --- a/seahub/templates/base_for_react.html +++ b/seahub/templates/base_for_react.html @@ -106,6 +106,7 @@ thumbnailSizeForOriginal: {{ thumbnail_size_for_original }}, repoPasswordMinLength: {{repo_password_min_length}}, canAddPublicRepo: {% if can_add_public_repo %} true {% else %} false {% endif %}, + enableOCMViaWebdav: {% if enable_ocm_via_webdav %} true {% else %} false {% endif %}, enableOCM: {% if enable_ocm %} true {% else %} false {% endif %}, ocmRemoteServers: (function () { var servers = []; diff --git a/seahub/urls.py b/seahub/urls.py index dde23281d2..54c954ad05 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -106,6 +106,8 @@ from seahub.api2.endpoints.ocm_repos import OCMReposDirView, OCMReposDownloadLin OCMReposUploadLinkView from seahub.api2.endpoints.custom_share_permissions import CustomSharePermissionsView, CustomSharePermissionView +from seahub.ocm_via_webdav.ocm_api import OCMProviderView + from seahub.api2.endpoints.repo_share_links import RepoShareLinks, RepoShareLink from seahub.api2.endpoints.repo_upload_links import RepoUploadLinks, RepoUploadLink @@ -194,6 +196,7 @@ urlpatterns = [ url(r'^shib-login/', shib_login, name="shib_login"), url(r'^oauth/', include('seahub.oauth.urls')), url(r'^thirdparty-editor/', include('seahub.thirdparty_editor.urls')), + url(r'^ocm-via-webdav/', include('seahub.ocm_via_webdav.urls')), url(r'^$', react_fake_view, name='libraries'), url(r'^robots\.txt$', TemplateView.as_view(template_name='robots.txt', content_type='text/plain')), @@ -474,7 +477,7 @@ urlpatterns = [ ## user::ocm # ocm inter-server api, interact with other server - url(r'ocm-provider/$', OCMProtocolView.as_view(), name='api-v2.1-ocm-protocol'), + url(r'ocm-provider/$', OCMProviderView.as_view(), name='api-v2.1-ocm-protocol'), url(r'' + OCM_ENDPOINT + 'shares/$', OCMSharesView.as_view(), name='api-v2.1-ocm-shares'), url(r'' + OCM_ENDPOINT + 'notifications/$', OCMNotificationsView.as_view(), name='api-v2.1-ocm-notifications'), diff --git a/seahub/views/__init__.py b/seahub/views/__init__.py index 2f22c9043b..218a0a4324 100644 --- a/seahub/views/__init__.py +++ b/seahub/views/__init__.py @@ -61,6 +61,7 @@ from seahub.settings import AVATAR_FILE_STORAGE, \ from seahub.wopi.settings import ENABLE_OFFICE_WEB_APP from seahub.onlyoffice.settings import ONLYOFFICE_DESKTOP_EDITORS_PORTAL_LOGIN from seahub.ocm.settings import ENABLE_OCM, OCM_REMOTE_SERVERS +from seahub.ocm_via_webdav.settings import ENABLE_OCM_VIA_WEBDAV from seahub.constants import HASH_URLS, PERMISSION_READ from seahub.group.settings import GROUP_IMPORT_MEMBERS_EXTRA_MSG @@ -1201,6 +1202,7 @@ def react_fake_view(request, **kwargs): 'additional_share_dialog_note': ADDITIONAL_SHARE_DIALOG_NOTE, 'additional_app_bottom_links': ADDITIONAL_APP_BOTTOM_LINKS, 'additional_about_dialog_links': ADDITIONAL_ABOUT_DIALOG_LINKS, + 'enable_ocm_via_webdav': ENABLE_OCM_VIA_WEBDAV, 'enable_ocm': ENABLE_OCM, 'ocm_remote_servers': OCM_REMOTE_SERVERS, 'enable_share_to_department': settings.ENABLE_SHARE_TO_DEPARTMENT,