diff --git a/frontend/src/components/dir-view-mode/dir-column-nav.js b/frontend/src/components/dir-view-mode/dir-column-nav.js index fc35ae27c4..babbbbe9c1 100644 --- a/frontend/src/components/dir-view-mode/dir-column-nav.js +++ b/frontend/src/components/dir-view-mode/dir-column-nav.js @@ -265,6 +265,7 @@ class DirColumnNav extends React.Component { currentRepoInfo={this.props.currentRepoInfo} selectedDirentList={this.props.selectedDirentList} onItemsMove={this.props.onItemsMove} + repoID={this.props.repoID} />) } diff --git a/frontend/src/components/metadata-manage/metadata-manage-view.js b/frontend/src/components/metadata-manage/metadata-manage-view.js new file mode 100644 index 0000000000..3840360c46 --- /dev/null +++ b/frontend/src/components/metadata-manage/metadata-manage-view.js @@ -0,0 +1,100 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Utils } from '../../utils/utils'; +import { gettext } from '../../utils/constants'; +import toaster from '../../components/toast'; +import seahubManageAPI from './seahub-manage-api'; + +const propTypes = { + repoID: PropTypes.string.isRequired, +}; + +class MetadataManageView extends React.Component { + + constructor(props) { + super(props); + this.state = { + isHighlight: false, + isShowOperationMenu: false, + }; + } + + onMouseEnter = () => { + this.setState({ + isShowOperationMenu: true, + isHighlight: true, + }); + }; + + onMouseOver = () => { + this.setState({ + isShowOperationMenu: true, + isHighlight: true, + }); + }; + + onMouseLeave = () => { + this.setState({ + isShowOperationMenu: false, + isHighlight: false, + }); + }; + + onItemMouseDown = (event) => { + event.stopPropagation(); + if (event.button === 2) { + return; + } + }; + + onClick = () => { + seahubManageAPI.getMetadataManagementEnabledStatus(this.props.repoID).then((res) => { + if (res.data.enabled){ + this.viewMetadata(); + } else if (confirm(gettext('Enable-Metadata-Manage?'))){ + seahubManageAPI.enableMetadataManagement(this.props.repoID).then((res) => { + this.viewMetadata(); + }).catch((error) => { + let errMessage = Utils.getErrorMsg(error); + toaster.danger(errMessage); + }); + } + }).catch((error) => { + let errMessage = Utils.getErrorMsg(error); + toaster.danger(errMessage); + }); + }; + + viewMetadata = () => { + + }; + + render() { + let hlClass = this.state.isHighlight ? 'tree-node-inner-hover ' : ''; + return ( +
+
+
{gettext('Metadata-View')} +
+ + +
+
+
+
+ ); + } +} + +MetadataManageView.propTypes = propTypes; + +export default MetadataManageView; diff --git a/frontend/src/components/metadata-manage/seahub-manage-api.js b/frontend/src/components/metadata-manage/seahub-manage-api.js new file mode 100644 index 0000000000..531b2c9f7c --- /dev/null +++ b/frontend/src/components/metadata-manage/seahub-manage-api.js @@ -0,0 +1,98 @@ +import axios from 'axios'; +import cookie from 'react-cookies'; +import { siteRoot } from '../../utils/constants'; + +class SeahubManageAPI { + init({ server, username, password, token }) { + this.server = server; + this.username = username; + this.password = password; + this.token = token; //none + if (this.token && this.server) { + this.req = axios.create({ + baseURL: this.server, + headers: { 'Authorization': 'Token ' + this.token }, + }); + } + return this; + } + + initForSeahubUsage({ siteRoot, xcsrfHeaders }) { + if (siteRoot && siteRoot.charAt(siteRoot.length-1) === '/') { + var server = siteRoot.substring(0, siteRoot.length-1); + this.server = server; + } else { + this.server = siteRoot; + } + + this.req = axios.create({ + headers: { + 'X-CSRFToken': xcsrfHeaders, + } + }); + return this; + } + + _sendPostRequest(url, form) { + if (form.getHeaders) { + return this.req.post(url, form, { + headers:form.getHeaders() + }); + } else { + return this.req.post(url, form); + } + } + + getMetadataManagementEnabledStatus(repoID) { + const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/'; + return this.req.get(url); + } + + enableMetadataManagement(repoID) { + const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/'; + return this.req.post(url); + } + + disableMetadataManagement(repoID) { + const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/'; + return this.req.delete(url); + } + + getMetadataRecords(repoID, params) { + const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/records/'; + return this.req.get(url, {params: params}); + } + + addMetadataRecords(repoID, parentDir, name) { + const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/records/'; + const data = { + 'parent_dir': parentDir, + 'name': name, + }; + return this.req.post(url, data); + } + + updateMetadataRecord(repoID, recordID, creator, createTime, modifier, modifyTime, parentDir, name) { + const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/records/' + recordID + '/'; + const data = { + 'creator': creator, + 'create_time': createTime, + 'modifier': modifier, + 'modify_time': modifyTime, + 'current_dir': parentDir, + 'name': name, + }; + return this.req.put(url, data); + } + + deleteMetadataRecord(repoID, recordID) { + const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/records/' + recordID + '/'; + return this.req.delete(url); + } +} + +const seahubManageAPI = new SeahubManageAPI(); +const xcsrfHeaders = cookie.load('sfcsrftoken'); +seahubManageAPI.initForSeahubUsage({ siteRoot, xcsrfHeaders }); + +export default seahubManageAPI; \ No newline at end of file diff --git a/frontend/src/components/tree-view/tree-view.js b/frontend/src/components/tree-view/tree-view.js index 4812080d60..25612f021d 100644 --- a/frontend/src/components/tree-view/tree-view.js +++ b/frontend/src/components/tree-view/tree-view.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import TextTranslation from '../../utils/text-translation'; import TreeNodeView from './tree-node-view'; +import MetadataManageView from '../metadata-manage/metadata-manage-view'; import ContextMenu from '../context-menu/context-menu'; import { hideMenu, showMenu } from '../context-menu/actions'; import { Utils } from '../../utils/utils'; @@ -19,6 +20,7 @@ const propTypes = { currentRepoInfo: PropTypes.object, selectedDirentList: PropTypes.array, onItemsMove: PropTypes.func, + repoID: PropTypes.string.isRequired, posX: PropTypes.number, posY: PropTypes.number, }; @@ -341,6 +343,9 @@ class TreeView extends React.Component { onNodeDragLeave={this.onNodeDragLeave} handleContextClick={this.handleContextClick} /> + {window.app.pageOptions.enableMetadataManagement && } 299: return api_error(status.HTTP_503_SERVICE_UNAVAILABLE, f'error from metadata server with code {response.status_code}: {response.reason}') - enable_recode.delete() + record.enabled = False + record.save() return Response({ 'success': True }) @@ -300,7 +309,7 @@ class MetadataManager(APIView): error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) -class MetadataManagerRecords(APIView): +class MetadataManageRecords(APIView): authentication_classes = (TokenAuthentication, SessionAuthentication) permission_classes = (IsAuthenticated, ) throttle_classes = (UserRateThrottle, ) @@ -321,11 +330,11 @@ class MetadataManagerRecords(APIView): #args check - parent_dir = request.data.get('parent_dir') - name = request.data.get('name') - page = request.data.get('page') - perpage = request.data.get('perpage') - is_dir = request.data.get('is_dir') + parent_dir = request.GET.get('parent_dir') + name = request.GET.get('name') + page = request.GET.get('page') + perpage = request.GET.get('perpage') + is_dir = request.GET.get('is_dir') if page: try: @@ -352,7 +361,7 @@ class MetadataManagerRecords(APIView): return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # metadata enable check - if not RepoMetadataEnable.objects.filter(repo_id=repo_id): + if not check_repo_metadata_is_enable(repo_id): error_msg = f'The metadata module is not enable for repo {repo_id}.' return api_error(status.HTTP_404_NOT_FOUND, error_msg) @@ -370,29 +379,47 @@ class MetadataManagerRecords(APIView): sql = f'SELECT `{COLUMN_ID.name}`, `{COLUMN_CREATOR.name}`, `{COLUMN_CREATE_TIME.name}`, `{COLUMN_MODIFIER.name}`, `{COLUMN_MODIFY_TIME.name}`, `{COLUMN_CURRENT_DIR.name}`, `{COLUMN_NAME.name}`, `{COLUMN_IS_DIR.name}` FROM `{TABLE.name}`' + parameters = [] + if parent_dir: - sql += f' WHERE `{COLUMN_CURRENT_DIR.name}` = "{parent_dir}"' + sql += f' WHERE `{COLUMN_CURRENT_DIR.name}` LIKE ?' + parameters.append(parent_dir) if name: - sql += f' AND `{COLUMN_NAME.name}` = "{name}"' + sql += f' AND `{COLUMN_NAME.name}` LIKE ?' + parameters.append(name) if is_dir: - sql += f' AND `{COLUMN_IS_DIR.name}` = "{is_dir}"' + sql += f' AND `{COLUMN_IS_DIR.name}` LIKE ?' + parameters.append(str(is_dir)) elif name: - sql += f' WHERE `{COLUMN_NAME.name}` = "{name}"' + sql += f' WHERE `{COLUMN_NAME.name}` LIKE ?' + parameters.append(name) + if is_dir: - sql += f' AND `{COLUMN_IS_DIR.name}` = "{is_dir}"' + sql += f' AND `{COLUMN_IS_DIR.name}` LIKE ?' + parameters.append(str(is_dir)) elif is_dir: - sql += f' WHERE `{COLUMN_IS_DIR.name}` = "{is_dir}"' + sql += f' WHERE `{COLUMN_IS_DIR.name}` LIKE ?' + parameters.append(str(is_dir)) + + sql += f' ORDER BY `{COLUMN_CURRENT_DIR.name}` ASC, `{COLUMN_IS_DIR.name}` DESC, `{COLUMN_NAME.name}` ASC' if page: sql += f' LIMIT {(page - 1) * perpage}, {page * perpage}' sql += ';' + post_data = { + 'sql': sql + } + + if parameters: + post_data['params'] = parameters + #query_result url = f'{MATEDATA_SERVER_URL}/api/v1/base/{repo_id}/query' headers = gen_headers(repo_id) - response = requests.post(url, json={'sql': sql}, headers=headers) + response = requests.post(url, json=post_data, headers=headers) if response.status_code < 200 or response.status_code > 299: return api_error(status.HTTP_503_SERVICE_UNAVAILABLE, f'error from metadata server with code {response.status_code}: {response.reason}') @@ -441,7 +468,7 @@ class MetadataManagerRecords(APIView): return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # metadata enable check - if not RepoMetadataEnable.objects.filter(repo_id=repo_id): + if not check_repo_metadata_is_enable(repo_id): error_msg = f'The metadata module is not enable for repo {repo_id}.' return api_error(status.HTTP_404_NOT_FOUND, error_msg) @@ -510,7 +537,7 @@ class MetadataManagerRecords(APIView): else: return api_error(status.HTTP_503_SERVICE_UNAVAILABLE, f'error from metadata server with code {response.status_code}: {response.reason}') -class MetadataManagerRecord(APIView): +class MetadataManageRecord(APIView): #authentication_classes = (TokenAuthentication, SessionAuthentication) #permission_classes = (IsAuthenticated, ) throttle_classes = (UserRateThrottle, ) @@ -546,7 +573,7 @@ class MetadataManagerRecord(APIView): return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # metadata enable check - if not RepoMetadataEnable.objects.filter(repo_id=repo_id): + if not check_repo_metadata_is_enable(repo_id): error_msg = f'The metadata module is not enable for repo {repo_id}.' return api_error(status.HTTP_404_NOT_FOUND, error_msg) @@ -635,7 +662,7 @@ class MetadataManagerRecord(APIView): return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # metadata enable check - if not RepoMetadataEnable.objects.filter(repo_id=repo_id): + if not check_repo_metadata_is_enable(repo_id): error_msg = f'The metadata module is not enable for repo {repo_id}.' return api_error(status.HTTP_404_NOT_FOUND, error_msg) diff --git a/seahub/repo_metadata_enable/__init__.py b/seahub/repo_metadata/__init__.py similarity index 100% rename from seahub/repo_metadata_enable/__init__.py rename to seahub/repo_metadata/__init__.py diff --git a/seahub/repo_metadata/models.py b/seahub/repo_metadata/models.py new file mode 100644 index 0000000000..d5313b0caa --- /dev/null +++ b/seahub/repo_metadata/models.py @@ -0,0 +1,13 @@ +import logging +from django.db import models + +logger = logging.getLogger(__name__) + +class RepoMetadata(models.Model): + + repo_id = models.CharField(max_length=36, primary_key=True, db_index=True) + modify_time = models.DateTimeField(auto_now=True) + enabled = models.BooleanField() + + class Meta: + db_table = 'repo_metadata' diff --git a/seahub/repo_metadata_enable/models.py b/seahub/repo_metadata_enable/models.py deleted file mode 100644 index 402a19f1f8..0000000000 --- a/seahub/repo_metadata_enable/models.py +++ /dev/null @@ -1,11 +0,0 @@ -import logging -from django.db import models - -logger = logging.getLogger(__name__) - -class RepoMetadataEnable(models.Model): - - repo_id = models.CharField(max_length=36, db_index=True) - - class Meta: - db_table = 'repo_metadata_enable' diff --git a/seahub/settings.py b/seahub/settings.py index 14197ad0c9..5d6bd0e175 100644 --- a/seahub/settings.py +++ b/seahub/settings.py @@ -269,7 +269,7 @@ INSTALLED_APPS = [ 'seahub.dingtalk', 'seahub.file_participants', 'seahub.repo_api_tokens', - 'seahub.repo_metadata_enable', + 'seahub.repo_metadata', 'seahub.abuse_reports', 'seahub.repo_auto_delete', 'seahub.ocm', diff --git a/seahub/templates/base_for_react.html b/seahub/templates/base_for_react.html index c725e6f22b..c69982a48f 100644 --- a/seahub/templates/base_for_react.html +++ b/seahub/templates/base_for_react.html @@ -153,6 +153,7 @@ canSetExProps: {% if can_set_ex_props %} true {% else %} false {% endif %}, enableSeaTableIntegration: {% if enable_seatable_integration %} true {% else %} false {% endif %}, isOrgContext: {% if org is not None %} true {% else %} false {% endif %}, + enableMetadataManagement: {% if enable_metadata_management %} true {% else %} false {% endif %}, } }; diff --git a/seahub/urls.py b/seahub/urls.py index d4e3a8c5f9..5e8cd6edc0 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -206,7 +206,7 @@ from seahub.ai.apis import LibrarySdocIndexes, Search, LibrarySdocIndex, TaskSta from seahub.wiki2.views import wiki_view from seahub.api2.endpoints.wiki2 import Wikis2View, Wiki2View, Wiki2ConfigView, Wiki2PagesView, Wiki2PageView from seahub.api2.endpoints.subscription import SubscriptionView, SubscriptionPlansView, SubscriptionLogsView -from seahub.api2.endpoints.metadata_manager import MetadataManagerRecords, MetadataManager, MetadataManagerRecord +from seahub.api2.endpoints.metadata_manager import MetadataManageRecords, MetadataManage, MetadataManageRecord urlpatterns = [ @@ -436,9 +436,9 @@ urlpatterns = [ re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/file/participants/$', FileParticipantsView.as_view(), name='api-v2.1-file-participants'), re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/file/participant/$', FileParticipantView.as_view(), name='api-v2.1-file-participant'), re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/related-users/$', RepoRelatedUsersView.as_view(), name='api-v2.1-related-user'), - re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/metadata/$', MetadataManager.as_view(), name='api-v2.1-metadata'), - re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/metadata/records/$', MetadataManagerRecords.as_view(), name='api-v2.1-metadata-records'), - re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/metadata/records/(?P[A-Za-z0-9_]+)/$', MetadataManagerRecord.as_view(), name='api-v2.1-metadata-record'), + re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/metadata/$', MetadataManage.as_view(), name='api-v2.1-metadata'), + re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/metadata/records/$', MetadataManageRecords.as_view(), name='api-v2.1-metadata-records'), + re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/metadata/records/(?P[A-Za-z0-9_]+)/$', MetadataManageRecord.as_view(), name='api-v2.1-metadata-record'), ## user:file:extended-props re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/extended-properties/$', ExtendedPropertiesView.as_view(), name='api-v2.1-extended-properties'), diff --git a/seahub/views/__init__.py b/seahub/views/__init__.py index af89a386c8..c7ea4dfc00 100644 --- a/seahub/views/__init__.py +++ b/seahub/views/__init__.py @@ -1093,5 +1093,6 @@ def react_fake_view(request, **kwargs): 'group_import_members_extra_msg': GROUP_IMPORT_MEMBERS_EXTRA_MSG, 'request_from_onlyoffice_desktop_editor': ONLYOFFICE_DESKTOP_EDITOR_HTTP_USER_AGENT in request.headers.get('user-agent', ''), 'enable_sso_to_thirdpart_website': settings.ENABLE_SSO_TO_THIRDPART_WEBSITE, - 'can_set_ex_props': DTABLE_WEB_SERVER and SEATABLE_EX_PROPS_BASE_API_TOKEN and EX_PROPS_TABLE and EX_EDITABLE_COLUMNS + 'can_set_ex_props': DTABLE_WEB_SERVER and SEATABLE_EX_PROPS_BASE_API_TOKEN and EX_PROPS_TABLE and EX_EDITABLE_COLUMNS, + 'enable_metadata_management': settings.ENABLE_METADATA_MANAGEMENT })