mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-23 09:11:15 +00:00
tags migrate
handle exist tag name
This commit is contained in:
parent
7ff4b52005
commit
b8fe71d5a2
@ -22,12 +22,12 @@ const { enableSeafileAI, enableSeafileOCR } = window.app.config;
|
|||||||
const propTypes = {
|
const propTypes = {
|
||||||
toggleDialog: PropTypes.func.isRequired,
|
toggleDialog: PropTypes.func.isRequired,
|
||||||
repoID: PropTypes.string.isRequired,
|
repoID: PropTypes.string.isRequired,
|
||||||
currentRepoInfo: PropTypes.object.isRequired
|
currentRepoInfo: PropTypes.object.isRequired,
|
||||||
|
usedRepoTags: PropTypes.array,
|
||||||
};
|
};
|
||||||
|
|
||||||
const LibSettingsDialog = ({ repoID, currentRepoInfo, toggleDialog, tab, showMigrateTip }) => {
|
const LibSettingsDialog = ({ repoID, currentRepoInfo, toggleDialog, tab, showMigrateTip, usedRepoTags, onMigrateSuccess }) => {
|
||||||
const [activeTab, setActiveTab] = useState(tab || TAB.HISTORY_SETTING);
|
const [activeTab, setActiveTab] = useState(tab || TAB.HISTORY_SETTING);
|
||||||
|
|
||||||
const toggleTab = useCallback((tab) => {
|
const toggleTab = useCallback((tab) => {
|
||||||
setActiveTab(tab);
|
setActiveTab(tab);
|
||||||
}, []);
|
}, []);
|
||||||
@ -202,6 +202,8 @@ const LibSettingsDialog = ({ repoID, currentRepoInfo, toggleDialog, tab, showMig
|
|||||||
toggleDialog={toggleDialog}
|
toggleDialog={toggleDialog}
|
||||||
enableMetadata={enableMetadata}
|
enableMetadata={enableMetadata}
|
||||||
showMigrateTip={showMigrateTip}
|
showMigrateTip={showMigrateTip}
|
||||||
|
usedRepoTags={usedRepoTags}
|
||||||
|
onMigrateSuccess={onMigrateSuccess}
|
||||||
/>
|
/>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
)}
|
)}
|
||||||
|
@ -33,6 +33,7 @@ const propTypes = {
|
|||||||
getMenuContainerSize: PropTypes.func,
|
getMenuContainerSize: PropTypes.func,
|
||||||
updateDirent: PropTypes.func,
|
updateDirent: PropTypes.func,
|
||||||
updateTreeNode: PropTypes.func,
|
updateTreeNode: PropTypes.func,
|
||||||
|
usedRepoTags: PropTypes.array,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirColumnNav extends React.Component {
|
class DirColumnNav extends React.Component {
|
||||||
@ -43,7 +44,7 @@ class DirColumnNav extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
isTreeDataLoading, userPerm, treeData, repoID, currentPath, currentRepoInfo, navRate = 0.25
|
isTreeDataLoading, userPerm, treeData, repoID, currentPath, currentRepoInfo, navRate = 0.25, usedRepoTags
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const flex = navRate ? '0 0 ' + navRate * 100 + '%' : '0 0 25%';
|
const flex = navRate ? '0 0 ' + navRate * 100 + '%' : '0 0 25%';
|
||||||
const select = this.props.inResizing ? 'none' : '';
|
const select = this.props.inResizing ? 'none' : '';
|
||||||
@ -74,9 +75,9 @@ class DirColumnNav extends React.Component {
|
|||||||
updateDirent={this.props.updateDirent}
|
updateDirent={this.props.updateDirent}
|
||||||
updateTreeNode={this.props.updateTreeNode}
|
updateTreeNode={this.props.updateTreeNode}
|
||||||
/>
|
/>
|
||||||
<DirViews repoID={repoID} currentPath={currentPath} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
<DirViews repoID={repoID} currentPath={currentPath} userPerm={userPerm} currentRepoInfo={currentRepoInfo} usedRepoTags={usedRepoTags} />
|
||||||
<DirTags repoID={repoID} currentPath={currentPath} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
<DirTags repoID={repoID} currentPath={currentPath} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
||||||
<DirOthers repoID={repoID} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
<DirOthers repoID={repoID} userPerm={userPerm} currentRepoInfo={currentRepoInfo} usedRepoTags={usedRepoTags} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -185,6 +185,7 @@ class DirColumnView extends React.Component {
|
|||||||
direntList={this.props.direntList}
|
direntList={this.props.direntList}
|
||||||
updateDirent={this.props.updateDirent}
|
updateDirent={this.props.updateDirent}
|
||||||
updateTreeNode={this.props.updateTreeNode}
|
updateTreeNode={this.props.updateTreeNode}
|
||||||
|
usedRepoTags={this.props.usedRepoTags}
|
||||||
/>
|
/>
|
||||||
<ResizeBar
|
<ResizeBar
|
||||||
resizeBarRef={this.resizeBarRef}
|
resizeBarRef={this.resizeBarRef}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { gettext } from '../../../utils/constants';
|
import { gettext } from '../../../utils/constants';
|
||||||
import { Utils } from '../../../utils/utils';
|
import { Utils } from '../../../utils/utils';
|
||||||
@ -12,9 +12,10 @@ import { TAB } from '../../../constants/repo-setting-tabs';
|
|||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
const DirOthers = ({ userPerm, repoID, currentRepoInfo }) => {
|
const DirOthers = ({ userPerm, repoID, currentRepoInfo, usedRepoTags }) => {
|
||||||
|
|
||||||
const showSettings = currentRepoInfo.is_admin; // repo owner, department admin, shared with 'Admin' permission
|
const showSettings = currentRepoInfo.is_admin; // repo owner, department admin, shared with 'Admin' permission
|
||||||
|
const repoName = currentRepoInfo.repo_name;
|
||||||
let [isSettingsDialogOpen, setSettingsDialogOpen] = useState(false);
|
let [isSettingsDialogOpen, setSettingsDialogOpen] = useState(false);
|
||||||
let [activeTab, setActiveTab] = useState(TAB.HISTORY_SETTING);
|
let [activeTab, setActiveTab] = useState(TAB.HISTORY_SETTING);
|
||||||
let [showMigrateTip, setShowMigrateTip] = useState(false);
|
let [showMigrateTip, setShowMigrateTip] = useState(false);
|
||||||
@ -23,6 +24,12 @@ const DirOthers = ({ userPerm, repoID, currentRepoInfo }) => {
|
|||||||
setSettingsDialogOpen(!isSettingsDialogOpen);
|
setSettingsDialogOpen(!isSettingsDialogOpen);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleMigrateSuccess = useCallback(() => {
|
||||||
|
setShowMigrateTip(false);
|
||||||
|
const serviceUrl = window.app.config.serviceURL;
|
||||||
|
window.location.href = serviceUrl + '/library/' + repoID + '/' + repoName + '/?tag=__all_tags';
|
||||||
|
}, [repoID, repoName]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribeUnselectFiles = eventBus.subscribe(EVENT_BUS_TYPE.OPEN_LIBRARY_SETTINGS_TAGS, () => {
|
const unsubscribeUnselectFiles = eventBus.subscribe(EVENT_BUS_TYPE.OPEN_LIBRARY_SETTINGS_TAGS, () => {
|
||||||
setSettingsDialogOpen(true);
|
setSettingsDialogOpen(true);
|
||||||
@ -79,6 +86,8 @@ const DirOthers = ({ userPerm, repoID, currentRepoInfo }) => {
|
|||||||
toggleDialog={toggleSettingsDialog}
|
toggleDialog={toggleSettingsDialog}
|
||||||
tab={activeTab}
|
tab={activeTab}
|
||||||
showMigrateTip={showMigrateTip}
|
showMigrateTip={showMigrateTip}
|
||||||
|
usedRepoTags={usedRepoTags}
|
||||||
|
onMigrateSuccess={handleMigrateSuccess}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isRepoHistoryDialogOpen && (
|
{isRepoHistoryDialogOpen && (
|
||||||
@ -97,6 +106,7 @@ DirOthers.propTypes = {
|
|||||||
userPerm: PropTypes.string,
|
userPerm: PropTypes.string,
|
||||||
repoID: PropTypes.string,
|
repoID: PropTypes.string,
|
||||||
currentRepoInfo: PropTypes.object.isRequired,
|
currentRepoInfo: PropTypes.object.isRequired,
|
||||||
|
usedRepoTags: PropTypes.array,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DirOthers;
|
export default DirOthers;
|
||||||
|
@ -7,15 +7,15 @@ import { EVENT_BUS_TYPE } from '../components/common/event-bus-type';
|
|||||||
|
|
||||||
const RepoInfoBarMigrate = () => {
|
const RepoInfoBarMigrate = () => {
|
||||||
|
|
||||||
const { enableMetadata } = useMetadataStatus();
|
const { enableMetadata, detailsSettings } = useMetadataStatus();
|
||||||
|
const tagsMigrated = detailsSettings?.tags_migrated;
|
||||||
const openMigrate = () => {
|
const openMigrate = () => {
|
||||||
eventBus.dispatch(EVENT_BUS_TYPE.OPEN_TREE_PANEL, () => eventBus.dispatch(EVENT_BUS_TYPE.OPEN_LIBRARY_SETTINGS_TAGS));
|
eventBus.dispatch(EVENT_BUS_TYPE.OPEN_TREE_PANEL, () => eventBus.dispatch(EVENT_BUS_TYPE.OPEN_LIBRARY_SETTINGS_TAGS));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="repo-info-bar-migrate mt-2">
|
<div className="repo-info-bar-migrate mt-2">
|
||||||
{enableMetadata ?
|
{enableMetadata && !tagsMigrated ?
|
||||||
(
|
(
|
||||||
<>
|
<>
|
||||||
{gettext('Tips: There are tags of old version. Please migrate tags to new version.')}
|
{gettext('Tips: There are tags of old version. Please migrate tags to new version.')}
|
||||||
|
@ -19,10 +19,11 @@ const langOptions = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const MetadataTagsStatusDialog = ({ value: oldValue, lang: oldLang, repoID, toggleDialog: toggle, submit, enableMetadata, showMigrateTip }) => {
|
const MetadataTagsStatusDialog = ({ value: oldValue, lang: oldLang, repoID, toggleDialog: toggle, submit, enableMetadata, showMigrateTip, usedRepoTags, onMigrateSuccess }) => {
|
||||||
const [value, setValue] = useState(oldValue);
|
const [value, setValue] = useState(oldValue);
|
||||||
const [lang, setLang] = useState(oldLang);
|
const [lang, setLang] = useState(oldLang);
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
const [migrated, setMigrated] = useState(false);
|
||||||
const [showTurnOffConfirmDialog, setShowTurnOffConfirmDialog] = useState(false);
|
const [showTurnOffConfirmDialog, setShowTurnOffConfirmDialog] = useState(false);
|
||||||
|
|
||||||
const onToggle = useCallback(() => {
|
const onToggle = useCallback(() => {
|
||||||
@ -46,8 +47,16 @@ const MetadataTagsStatusDialog = ({ value: oldValue, lang: oldLang, repoID, togg
|
|||||||
}, [lang, repoID, submit, toggle, value]);
|
}, [lang, repoID, submit, toggle, value]);
|
||||||
|
|
||||||
const migrateTag = useCallback(() => {
|
const migrateTag = useCallback(() => {
|
||||||
// TODO backend migrate old tags
|
tagsAPI.migrateTags(repoID, usedRepoTags).then(res => {
|
||||||
}, []);
|
setMigrated(true);
|
||||||
|
toaster.success(gettext('Tags migrated successfully'));
|
||||||
|
onMigrateSuccess && onMigrateSuccess();
|
||||||
|
}).catch(error => {
|
||||||
|
const errorMsg = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errorMsg);
|
||||||
|
setMigrated(false);
|
||||||
|
});
|
||||||
|
}, [repoID, usedRepoTags, onMigrateSuccess]);
|
||||||
|
|
||||||
const turnOffConfirmToggle = useCallback(() => {
|
const turnOffConfirmToggle = useCallback(() => {
|
||||||
setShowTurnOffConfirmDialog(!showTurnOffConfirmDialog);
|
setShowTurnOffConfirmDialog(!showTurnOffConfirmDialog);
|
||||||
@ -110,7 +119,13 @@ const MetadataTagsStatusDialog = ({ value: oldValue, lang: oldLang, repoID, togg
|
|||||||
{showMigrateTip &&
|
{showMigrateTip &&
|
||||||
<FormGroup className="mt-6">
|
<FormGroup className="mt-6">
|
||||||
<p>{gettext('This library contains tags of old version. Do you like to migrate the tags to new version?')}</p>
|
<p>{gettext('This library contains tags of old version. Do you like to migrate the tags to new version?')}</p>
|
||||||
<Button color="primary" onClick={migrateTag}>{gettext('Migrate old version tags')}</Button>
|
<Button
|
||||||
|
color="primary"
|
||||||
|
onClick={migrateTag}
|
||||||
|
disabled={migrated}
|
||||||
|
>
|
||||||
|
{migrated ? gettext('Migrated') : gettext('Migrate old version tags')}
|
||||||
|
</Button>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
}
|
}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
@ -136,6 +151,8 @@ MetadataTagsStatusDialog.propTypes = {
|
|||||||
submit: PropTypes.func.isRequired,
|
submit: PropTypes.func.isRequired,
|
||||||
enableMetadata: PropTypes.bool.isRequired,
|
enableMetadata: PropTypes.bool.isRequired,
|
||||||
showMigrateTip: PropTypes.bool,
|
showMigrateTip: PropTypes.bool,
|
||||||
|
repoTags: PropTypes.array,
|
||||||
|
onMigrateSuccess: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MetadataTagsStatusDialog;
|
export default MetadataTagsStatusDialog;
|
||||||
|
@ -2350,6 +2350,7 @@ class LibContentView extends React.Component {
|
|||||||
if (!currentDirent && currentMode !== METADATA_MODE && currentMode !== TAGS_MODE) {
|
if (!currentDirent && currentMode !== METADATA_MODE && currentMode !== TAGS_MODE) {
|
||||||
detailPath = Utils.getDirName(this.state.path);
|
detailPath = Utils.getDirName(this.state.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
const detailDirent = currentDirent || currentNode?.object || null;
|
const detailDirent = currentDirent || currentNode?.object || null;
|
||||||
return (
|
return (
|
||||||
<MetadataStatusProvider repoID={repoID} repoInfo={currentRepoInfo} hideMetadataView={this.hideMetadataView} statusCallback={this.metadataStatusCallback} >
|
<MetadataStatusProvider repoID={repoID} repoInfo={currentRepoInfo} hideMetadataView={this.hideMetadataView} statusCallback={this.metadataStatusCallback} >
|
||||||
|
@ -138,6 +138,14 @@ class TagsManagerAPI {
|
|||||||
return this.req.post(url, params);
|
return this.req.post(url, params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
migrateTags = (repoID, usedRepoTags) => {
|
||||||
|
const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/migrate-tags/';
|
||||||
|
const params = {
|
||||||
|
tag_ids: usedRepoTags.map(tag => tag.id),
|
||||||
|
};
|
||||||
|
return this.req.post(url, params);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagsAPI = new TagsManagerAPI();
|
const tagsAPI = new TagsManagerAPI();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import posixpath
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from rest_framework.authentication import SessionAuthentication
|
from rest_framework.authentication import SessionAuthentication
|
||||||
@ -17,11 +18,12 @@ from seahub.repo_metadata.utils import add_init_metadata_task, recognize_faces,
|
|||||||
get_unmodifiable_columns, can_read_metadata, init_faces, \
|
get_unmodifiable_columns, can_read_metadata, init_faces, \
|
||||||
extract_file_details, get_table_by_name, remove_faces_table, FACES_SAVE_PATH, \
|
extract_file_details, get_table_by_name, remove_faces_table, FACES_SAVE_PATH, \
|
||||||
init_tags, init_tag_self_link_columns, remove_tags_table, add_init_face_recognition_task, init_ocr, \
|
init_tags, init_tag_self_link_columns, remove_tags_table, add_init_face_recognition_task, init_ocr, \
|
||||||
remove_ocr_column, get_update_record, update_people_cover_photo
|
remove_ocr_column, get_update_record, update_people_cover_photo, gen_unique_tag_name
|
||||||
from seahub.repo_metadata.metadata_server_api import MetadataServerAPI, list_metadata_view_records
|
from seahub.repo_metadata.metadata_server_api import MetadataServerAPI, list_metadata_view_records, list_eligible_metadata_records
|
||||||
from seahub.utils.repo import is_repo_admin
|
from seahub.utils.repo import is_repo_admin
|
||||||
from seaserv import seafile_api
|
from seaserv import seafile_api
|
||||||
from seahub.repo_metadata.constants import FACE_RECOGNITION_VIEW_ID, METADATA_RECORD_UPDATE_LIMIT
|
from seahub.repo_metadata.constants import FACE_RECOGNITION_VIEW_ID, METADATA_RECORD_UPDATE_LIMIT
|
||||||
|
from seahub.file_tags.models import FileTags
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -2780,3 +2782,174 @@ class PeopleCoverPhoto(APIView):
|
|||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
return Response({'success': True})
|
return Response({'success': True})
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataMigrateTags(APIView):
|
||||||
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
|
permission_classes = (IsAuthenticated,)
|
||||||
|
throttle_classes = (UserRateThrottle,)
|
||||||
|
|
||||||
|
def post(self, request, repo_id):
|
||||||
|
tag_ids = request.data.get('tag_ids')
|
||||||
|
if not tag_ids:
|
||||||
|
error_msg = 'tag_ids invalid'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
metadata = RepoMetadata.objects.filter(repo_id=repo_id).first()
|
||||||
|
if not metadata or not metadata.enabled or not metadata.tags_enabled:
|
||||||
|
error_msg = f'The tags is disabled for repo {repo_id}.'
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
# resource check
|
||||||
|
repo = seafile_api.get_repo(repo_id)
|
||||||
|
if not repo:
|
||||||
|
error_msg = 'Library %s not found.' % repo_id
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
if not is_repo_admin(request.user.username, repo_id):
|
||||||
|
error_msg = 'Permission denied.'
|
||||||
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
|
# get all records
|
||||||
|
from seafevents.repo_metadata.constants import METADATA_TABLE
|
||||||
|
from seafevents.repo_metadata.constants import TAGS_TABLE
|
||||||
|
|
||||||
|
try:
|
||||||
|
basic_filters = [{'column_key': METADATA_TABLE.columns.is_dir.name, 'filter_predicate': 'is', 'filter_term': 'file'}]
|
||||||
|
view = {
|
||||||
|
'filters': [],
|
||||||
|
'basic_filters': basic_filters
|
||||||
|
}
|
||||||
|
filter_columns = [METADATA_TABLE.columns.id.name, METADATA_TABLE.columns.file_name.name, METADATA_TABLE.columns.parent_dir.name]
|
||||||
|
results = list_eligible_metadata_records(repo_id, request.user.username, view, filter_columns)
|
||||||
|
records = results.get('results')
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
|
# 每个record对应的文件路径
|
||||||
|
records_dict = {} # {file_path: record_id}
|
||||||
|
for record in records:
|
||||||
|
file_path = posixpath.join(record.get(METADATA_TABLE.columns.parent_dir.name), record.get(METADATA_TABLE.columns.file_name.name))
|
||||||
|
records_dict[file_path] = record.get(METADATA_TABLE.columns.id.name)
|
||||||
|
|
||||||
|
# list old tag info
|
||||||
|
old_repo_tag_info = {} # {repo_tag_id: {name: '', color: '', file_paths: [file_path1, file_path2]}}
|
||||||
|
try:
|
||||||
|
tagged_file_objs = FileTags.objects.filter(
|
||||||
|
repo_tag__id__in=tag_ids).select_related('repo_tag', 'file_uuid')
|
||||||
|
for tagged_file_obj in tagged_file_objs:
|
||||||
|
repo_tag_id = tagged_file_obj.repo_tag.id
|
||||||
|
parent_path = tagged_file_obj.file_uuid.parent_path
|
||||||
|
filename = tagged_file_obj.file_uuid.filename
|
||||||
|
file_path = posixpath.join(parent_path, filename)
|
||||||
|
if repo_tag_id not in old_repo_tag_info:
|
||||||
|
old_repo_tag_info[repo_tag_id] = {
|
||||||
|
'name': tagged_file_obj.repo_tag.name,
|
||||||
|
'color': tagged_file_obj.repo_tag.color,
|
||||||
|
'file_paths': []
|
||||||
|
}
|
||||||
|
old_repo_tag_info[repo_tag_id]['file_paths'].append(file_path)
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(err)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
print(old_repo_tag_info, '---old_repo_tag_info')
|
||||||
|
|
||||||
|
# file_path to record_id
|
||||||
|
repo_tag_id_map = {} # {repo_tag_id: [record_id1, record_id2]}
|
||||||
|
tags_data = [] # [{name: '', color: ''}]
|
||||||
|
for repo_tag_id, tag_data in old_repo_tag_info.items():
|
||||||
|
repo_tag_id_map[repo_tag_id] = []
|
||||||
|
for file_path in tag_data['file_paths']:
|
||||||
|
record_id = records_dict.get(file_path, '')
|
||||||
|
if record_id:
|
||||||
|
repo_tag_id_map[repo_tag_id].append(record_id)
|
||||||
|
tags_data.append({
|
||||||
|
TAGS_TABLE.columns.name.name: tag_data['name'],
|
||||||
|
TAGS_TABLE.columns.color.name: tag_data['color'],
|
||||||
|
})
|
||||||
|
|
||||||
|
# {"tags_data":[{"_tag_color":"#46A1FD","_tag_name":"va"}]}
|
||||||
|
metadata_server_api = MetadataServerAPI(repo_id, request.user.username)
|
||||||
|
try:
|
||||||
|
tags_table = get_table_by_name(metadata_server_api, TAGS_TABLE.name)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
|
if not tags_table:
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, 'tags table not found')
|
||||||
|
|
||||||
|
tags_table_id = tags_table['id']
|
||||||
|
exist_tags = []
|
||||||
|
new_tags = []
|
||||||
|
sql = f'SELECT `{TAGS_TABLE.columns.name.name}` FROM {TAGS_TABLE.name}'
|
||||||
|
|
||||||
|
try:
|
||||||
|
exist_rows = metadata_server_api.query_rows(sql)
|
||||||
|
exist_tags = exist_rows.get('results', [])
|
||||||
|
if exist_tags:
|
||||||
|
exist_tags = [tag_data.get(TAGS_TABLE.columns.name.name, '') for tag_data in exist_tags]
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
# handle exist tags
|
||||||
|
if exist_tags:
|
||||||
|
for index, tag_data in enumerate(tags_data):
|
||||||
|
tag_name = tag_data.get(TAGS_TABLE.columns.name.name, '')
|
||||||
|
if tag_name not in exist_tags:
|
||||||
|
new_tags.append(tag_data)
|
||||||
|
else:
|
||||||
|
unique_tag_name = gen_unique_tag_name(tag_name, exist_tags)
|
||||||
|
new_tags.append({
|
||||||
|
TAGS_TABLE.columns.color.name: tag_data.get(TAGS_TABLE.columns.color.name, ''),
|
||||||
|
TAGS_TABLE.columns.name.name: unique_tag_name
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
new_tags = tags_data
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = metadata_server_api.insert_rows(tags_table_id, new_tags)
|
||||||
|
row_ids = resp.get('row_ids', [])
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
# record_id : tags
|
||||||
|
# handle file_tags_data
|
||||||
|
new_tags_info_array = []
|
||||||
|
for index, old_tag_id in enumerate(repo_tag_id_map):
|
||||||
|
new_tag_id = row_ids[index]
|
||||||
|
record_ids = repo_tag_id_map[old_tag_id]
|
||||||
|
new_tags_info_array.append({
|
||||||
|
'record_ids': record_ids,
|
||||||
|
'tag_id': new_tag_id
|
||||||
|
})
|
||||||
|
record_id_tag_id_map = {}
|
||||||
|
for tag_info in new_tags_info_array:
|
||||||
|
record_ids = tag_info.get('record_ids', [])
|
||||||
|
tag_id = tag_info.get('tag_id', '')
|
||||||
|
for record_id in record_ids:
|
||||||
|
if record_id not in record_id_tag_id_map:
|
||||||
|
record_id_tag_id_map[record_id] = []
|
||||||
|
record_id_tag_id_map[record_id].append(tag_id)
|
||||||
|
|
||||||
|
try:
|
||||||
|
metadata_server_api.insert_link(TAGS_TABLE.file_link_id, METADATA_TABLE.id, record_id_tag_id_map)
|
||||||
|
record = RepoMetadata.objects.filter(repo_id=repo_id).first()
|
||||||
|
if not record.details_settings:
|
||||||
|
details_settings = {}
|
||||||
|
else:
|
||||||
|
details_settings = json.loads(record.details_settings)
|
||||||
|
details_settings['tags_migrated'] = True
|
||||||
|
record.details_settings = json.dumps(details_settings)
|
||||||
|
|
||||||
|
record.save()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
return Response({'success': True})
|
||||||
|
@ -78,6 +78,26 @@ def list_metadata_view_records(repo_id, user, view, tags_enabled, start=0, limit
|
|||||||
return response_results
|
return response_results
|
||||||
|
|
||||||
|
|
||||||
|
def list_eligible_metadata_records(repo_id, user, view, filter_columns):
|
||||||
|
from seafevents.repo_metadata.constants import METADATA_TABLE
|
||||||
|
from seafevents.repo_metadata.utils import gen_view_data_sql
|
||||||
|
metadata_server_api = MetadataServerAPI(repo_id, user)
|
||||||
|
columns = metadata_server_api.list_columns(METADATA_TABLE.id).get('columns')
|
||||||
|
tags_data = {'metadata': [], 'results': []}
|
||||||
|
|
||||||
|
sql = gen_view_data_sql(METADATA_TABLE, columns, view, 0, 0, {'tags_data': tags_data, 'username': user})
|
||||||
|
query_fields_str = ''
|
||||||
|
for column in columns:
|
||||||
|
column_name = column.get('name')
|
||||||
|
if column_name in filter_columns:
|
||||||
|
column_name_str = '`%s`, ' % column_name
|
||||||
|
query_fields_str += column_name_str
|
||||||
|
query_fields_str = query_fields_str.strip(', ')
|
||||||
|
sql = sql.replace('*', query_fields_str)
|
||||||
|
response_results = metadata_server_api.query_rows(sql, [])
|
||||||
|
return response_results
|
||||||
|
|
||||||
|
|
||||||
def parse_response(response):
|
def parse_response(response):
|
||||||
if response.status_code >= 300 or response.status_code < 200:
|
if response.status_code >= 300 or response.status_code < 200:
|
||||||
raise ConnectionError(response.status_code, response.text)
|
raise ConnectionError(response.status_code, response.text)
|
||||||
|
@ -3,7 +3,7 @@ from .apis import MetadataRecognizeFaces, MetadataRecords, MetadataManage, Metad
|
|||||||
MetadataFolders, MetadataViews, MetadataViewsMoveView, MetadataViewsDetailView, MetadataViewsDuplicateView, FacesRecords, \
|
MetadataFolders, MetadataViews, MetadataViewsMoveView, MetadataViewsDetailView, MetadataViewsDuplicateView, FacesRecords, \
|
||||||
FaceRecognitionManage, FacesRecord, MetadataExtractFileDetails, PeoplePhotos, MetadataTagsStatusManage, MetadataTags, \
|
FaceRecognitionManage, FacesRecord, MetadataExtractFileDetails, PeoplePhotos, MetadataTagsStatusManage, MetadataTags, \
|
||||||
MetadataTagsLinks, MetadataFileTags, MetadataTagFiles, MetadataMergeTags, MetadataTagsFiles, MetadataDetailsSettingsView, \
|
MetadataTagsLinks, MetadataFileTags, MetadataTagFiles, MetadataMergeTags, MetadataTagsFiles, MetadataDetailsSettingsView, \
|
||||||
MetadataOCRManageView, PeopleCoverPhoto
|
MetadataOCRManageView, PeopleCoverPhoto, MetadataMigrateTags
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
re_path(r'^$', MetadataManage.as_view(), name='api-v2.1-metadata'),
|
re_path(r'^$', MetadataManage.as_view(), name='api-v2.1-metadata'),
|
||||||
@ -43,4 +43,5 @@ urlpatterns = [
|
|||||||
re_path(r'^tag-files/(?P<tag_id>.+)/$', MetadataTagFiles.as_view(), name='api-v2.1-metadata-tag-files'),
|
re_path(r'^tag-files/(?P<tag_id>.+)/$', MetadataTagFiles.as_view(), name='api-v2.1-metadata-tag-files'),
|
||||||
re_path(r'^merge-tags/$', MetadataMergeTags.as_view(), name='api-v2.1-metadata-merge-tags'),
|
re_path(r'^merge-tags/$', MetadataMergeTags.as_view(), name='api-v2.1-metadata-merge-tags'),
|
||||||
re_path(r'^tags-files/$', MetadataTagsFiles.as_view(), name='api-v2.1-metadata-tags-files'),
|
re_path(r'^tags-files/$', MetadataTagsFiles.as_view(), name='api-v2.1-metadata-tags-files'),
|
||||||
|
re_path(r'^migrate-tags/$', MetadataMigrateTags.as_view(), name='api-v2.1-metadata-migrate-tags'),
|
||||||
]
|
]
|
||||||
|
@ -73,6 +73,11 @@ def gen_unique_id(id_set, length=4):
|
|||||||
return _id
|
return _id
|
||||||
_id = generator_base64_code(length)
|
_id = generator_base64_code(length)
|
||||||
|
|
||||||
|
def gen_unique_tag_name(tag_name, exist_tags, counter=1):
|
||||||
|
new_name = f'{tag_name}({counter})'
|
||||||
|
if new_name not in exist_tags:
|
||||||
|
return new_name
|
||||||
|
return gen_unique_tag_name(tag_name, exist_tags, counter + 1)
|
||||||
|
|
||||||
def get_face_columns():
|
def get_face_columns():
|
||||||
from seafevents.repo_metadata.constants import FACES_TABLE
|
from seafevents.repo_metadata.constants import FACES_TABLE
|
||||||
|
Loading…
Reference in New Issue
Block a user