1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-19 18:29:23 +00:00

ex-props support folder (#5617)

* ex-props support folder

* feat: add front code

* support empty folder whose hash is empty-sha1

---------

Co-authored-by: er-pai-r <18335219360@163.com>
This commit is contained in:
Alex Happy
2023-08-30 22:30:23 +08:00
committed by GitHub
parent 6e9595f33b
commit 395790a879
3 changed files with 118 additions and 95 deletions

View File

@@ -17,7 +17,7 @@ class ExtraAttributesDialog extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
const { direntDetail } = props; const { direntDetail, direntType } = props;
this.state = { this.state = {
animationEnd: false, animationEnd: false,
isLoading: true, isLoading: true,
@@ -26,8 +26,12 @@ class ExtraAttributesDialog extends Component {
columns: [], columns: [],
errorMsg: '', errorMsg: '',
}; };
const direntDetailId = direntDetail.id; if (direntType === 'dir') {
this.isEmptyFile = false;
} else {
const direntDetailId = direntDetail?.id || '';
this.isEmptyFile = direntDetailId === '0'.repeat(direntDetailId.length); this.isEmptyFile = direntDetailId === '0'.repeat(direntDetailId.length);
}
this.isExist = false; this.isExist = false;
this.modalRef = React.createRef(); this.modalRef = React.createRef();
} }
@@ -243,6 +247,7 @@ class ExtraAttributesDialog extends Component {
ExtraAttributesDialog.propTypes = { ExtraAttributesDialog.propTypes = {
repoID: PropTypes.string, repoID: PropTypes.string,
filePath: PropTypes.string, filePath: PropTypes.string,
direntType: PropTypes.string,
direntDetail: PropTypes.object, direntDetail: PropTypes.object,
onToggle: PropTypes.func, onToggle: PropTypes.func,
}; };

View File

@@ -63,10 +63,9 @@ class DetailListView extends React.Component {
this.setState({ isShowExtraAttributes: !this.state.isShowExtraAttributes }); this.setState({ isShowExtraAttributes: !this.state.isShowExtraAttributes });
} }
render() { renderTags = () => {
let { direntType, direntDetail, fileTagList } = this.props; const { direntType, direntDetail, fileTagList } = this.props;
let position = this.getDirentPosition(); const position = this.getDirentPosition();
let direntPath = this.getDirentPath();
if (direntType === 'dir') { if (direntType === 'dir') {
return ( return (
<table className="table-thead-hidden"> <table className="table-thead-hidden">
@@ -76,12 +75,20 @@ class DetailListView extends React.Component {
<tbody> <tbody>
<tr><th>{gettext('Location')}</th><td>{position}</td></tr> <tr><th>{gettext('Location')}</th><td>{position}</td></tr>
<tr><th>{gettext('Last Update')}</th><td>{moment(direntDetail.mtime).format('YYYY-MM-DD')}</td></tr> <tr><th>{gettext('Last Update')}</th><td>{moment(direntDetail.mtime).format('YYYY-MM-DD')}</td></tr>
{direntDetail.permission === 'rw' && (
<tr className="file-extra-attributes">
<th colSpan={2}>
<div className="edit-file-extra-attributes-btn" onClick={this.toggleExtraAttributesDialog}>
{gettext('Edit extra properties')}
</div>
</th>
</tr>
)}
</tbody> </tbody>
</table> </table>
); );
} else { }
return ( return (
<Fragment>
<table className="table-thead-hidden"> <table className="table-thead-hidden">
<thead> <thead>
<tr><th width="35%"></th><th width="65%"></th></tr> <tr><th width="35%"></th><th width="65%"></th></tr>
@@ -117,6 +124,16 @@ class DetailListView extends React.Component {
)} )}
</tbody> </tbody>
</table> </table>
);
}
render() {
const { direntType, direntDetail, fileTagList } = this.props;
const direntPath = this.getDirentPath();
return (
<Fragment>
{this.renderTags()}
{this.state.isEditFileTagShow && {this.state.isEditFileTagShow &&
<ModalPortal> <ModalPortal>
<EditFileTagDialog <EditFileTagDialog
@@ -132,6 +149,7 @@ class DetailListView extends React.Component {
<ExtraAttributesDialog <ExtraAttributesDialog
repoID={this.props.repoID} repoID={this.props.repoID}
filePath={direntPath} filePath={direntPath}
direntType={direntType}
direntDetail={direntDetail} direntDetail={direntDetail}
onToggle={this.toggleExtraAttributesDialog} onToggle={this.toggleExtraAttributesDialog}
/> />
@@ -140,7 +158,6 @@ class DetailListView extends React.Component {
); );
} }
} }
}
DetailListView.defaultProps = { DetailListView.defaultProps = {
fileTagList: [], fileTagList: [],

View File

@@ -1,6 +1,7 @@
import json import json
import logging import logging
import os import os
import stat
from datetime import datetime from datetime import datetime
from rest_framework import status from rest_framework import status
@@ -51,7 +52,7 @@ class ExtendedPropertiesView(APIView):
return api_error(status.HTTP_400_BAD_REQUEST, 'path invalid') return api_error(status.HTTP_400_BAD_REQUEST, 'path invalid')
path = normalize_file_path(path) path = normalize_file_path(path)
parent_dir = os.path.dirname(path) parent_dir = os.path.dirname(path)
file_name = os.path.basename(path) dirent_name = os.path.basename(path)
props_data_str = request.data.get('props_data') props_data_str = request.data.get('props_data')
if not props_data_str or not isinstance(props_data_str, str): if not props_data_str or not isinstance(props_data_str, str):
return api_error(status.HTTP_400_BAD_REQUEST, 'props_data invalid') return api_error(status.HTTP_400_BAD_REQUEST, 'props_data invalid')
@@ -67,9 +68,9 @@ class ExtendedPropertiesView(APIView):
return api_error(status.HTTP_404_NOT_FOUND, 'Library not found') return api_error(status.HTTP_404_NOT_FOUND, 'Library not found')
dirent = seafile_api.get_dirent_by_path(repo_id, path) dirent = seafile_api.get_dirent_by_path(repo_id, path)
if not dirent: if not dirent:
return api_error(status.HTTP_404_NOT_FOUND, 'File %s not found' % path) return api_error(status.HTTP_404_NOT_FOUND, 'File or folder %s not found' % path)
if dirent.obj_id == EMPTY_SHA1: if not stat.S_ISDIR(dirent.mode) and dirent.obj_id == EMPTY_SHA1:
return api_error(status.HTTP_400_BAD_REQUEST, 'File %s is empty' % path) return api_error(status.HTTP_400_BAD_REQUEST, 'File or folder %s is empty' % path)
# permission check # permission check
if not parse_repo_perm(check_folder_permission(request, repo_id, parent_dir)).can_edit_on_web: if not parse_repo_perm(check_folder_permission(request, repo_id, parent_dir)).can_edit_on_web:
@@ -90,8 +91,10 @@ class ExtendedPropertiesView(APIView):
if error_msg: if error_msg:
return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg) return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg)
## check existed props row ## check existed props row
file_uuid = FileUUIDMap.objects.get_or_create_fileuuidmap(repo_id, parent_dir, file_name, False).uuid.hex file_uuid = None
sql = f"SELECT COUNT(1) as `count` FROM `{EX_PROPS_TABLE}` WHERE `UUID`='{file_uuid}'" if not stat.S_ISDIR(dirent.mode):
file_uuid = FileUUIDMap.objects.get_or_create_fileuuidmap(repo_id, parent_dir, dirent_name, False).uuid.hex
sql = f"SELECT COUNT(1) as `count` FROM `{EX_PROPS_TABLE}` WHERE `Repo ID`='{repo_id}' AND `Path`='{path}'"
result = seatable_api.query(sql) result = seatable_api.query(sql)
count = result['results'][0]['count'] count = result['results'][0]['count']
if count > 0: if count > 0:
@@ -100,7 +103,7 @@ class ExtendedPropertiesView(APIView):
props_data = {column_name: value for column_name, value in props_data.items() if column_name in EX_EDITABLE_COLUMNS} props_data = {column_name: value for column_name, value in props_data.items() if column_name in EX_EDITABLE_COLUMNS}
props_data.update({ props_data.update({
'Repo ID': repo_id, 'Repo ID': repo_id,
'File': file_name, 'File': dirent_name,
'Path': path, 'Path': path,
'UUID': file_uuid, 'UUID': file_uuid,
'创建日期': str(datetime.fromtimestamp(dirent.mtime)), '创建日期': str(datetime.fromtimestamp(dirent.mtime)),
@@ -113,7 +116,7 @@ class ExtendedPropertiesView(APIView):
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error') return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error')
## query ## query
sql = f"SELECT * FROM {EX_PROPS_TABLE} WHERE `UUID`='{file_uuid}'" sql = f"SELECT * FROM {EX_PROPS_TABLE} WHERE `Repo ID`='{repo_id}' AND `Path`='{path}'"
try: try:
result = seatable_api.query(sql) result = seatable_api.query(sql)
except Exception as e: except Exception as e:
@@ -141,9 +144,9 @@ class ExtendedPropertiesView(APIView):
repo = seafile_api.get_repo(repo_id) repo = seafile_api.get_repo(repo_id)
if not repo: if not repo:
return api_error(status.HTTP_404_NOT_FOUND, 'Library not found') return api_error(status.HTTP_404_NOT_FOUND, 'Library not found')
file_id = seafile_api.get_file_id_by_path(repo_id, path) dirent = seafile_api.get_dirent_by_path(repo_id, path)
if not file_id: if not dirent:
return api_error(status.HTTP_404_NOT_FOUND, 'File %s not found' % path) return api_error(status.HTTP_404_NOT_FOUND, 'File or folder %s not found' % path)
# permission check # permission check
if not parse_repo_perm(check_folder_permission(request, repo_id, parent_dir)).can_edit_on_web: if not parse_repo_perm(check_folder_permission(request, repo_id, parent_dir)).can_edit_on_web:
@@ -164,9 +167,11 @@ class ExtendedPropertiesView(APIView):
if error_msg: if error_msg:
return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg) return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg)
## query ## query
file_name = os.path.basename(path) dirent_name = os.path.basename(path)
file_uuid = FileUUIDMap.objects.get_or_create_fileuuidmap(repo_id, parent_dir, file_name, False).uuid.hex file_uuid = None
sql = f"SELECT * FROM {EX_PROPS_TABLE} WHERE `UUID`='{file_uuid}'" if not stat.S_ISDIR(dirent.mode):
file_uuid = FileUUIDMap.objects.get_or_create_fileuuidmap(repo_id, parent_dir, dirent_name, False).uuid.hex
sql = f"SELECT * FROM `{EX_PROPS_TABLE}` WHERE `Repo ID`='{repo_id}' AND `Path`='{path}'"
try: try:
result = seatable_api.query(sql) result = seatable_api.query(sql)
except Exception as e: except Exception as e:
@@ -178,7 +183,7 @@ class ExtendedPropertiesView(APIView):
else: else:
row = { row = {
'Repo ID': repo_id, 'Repo ID': repo_id,
'File': file_name, 'File': dirent_name,
'Path': path, 'Path': path,
'UUID': file_uuid 'UUID': file_uuid
} }
@@ -216,9 +221,9 @@ class ExtendedPropertiesView(APIView):
repo = seafile_api.get_repo(repo_id) repo = seafile_api.get_repo(repo_id)
if not repo: if not repo:
return api_error(status.HTTP_404_NOT_FOUND, 'Library not found') return api_error(status.HTTP_404_NOT_FOUND, 'Library not found')
file_id = seafile_api.get_file_id_by_path(repo_id, path) dirent = seafile_api.get_dirent_by_path(repo_id, path)
if not file_id: if not dirent:
return api_error(status.HTTP_404_NOT_FOUND, 'File %s not found' % path) return api_error(status.HTTP_404_NOT_FOUND, 'File or folder %s not found' % path)
# permission check # permission check
if not parse_repo_perm(check_folder_permission(request, repo_id, parent_dir)).can_edit_on_web: if not parse_repo_perm(check_folder_permission(request, repo_id, parent_dir)).can_edit_on_web:
@@ -239,13 +244,11 @@ class ExtendedPropertiesView(APIView):
if error_msg: if error_msg:
return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg) return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg)
## check existed props row ## check existed props row
file_name = os.path.basename(path) sql = f"SELECT * FROM `{EX_PROPS_TABLE}` WHERE `Repo ID`='{repo_id}' AND `Path`='{path}'"
file_uuid = FileUUIDMap.objects.get_or_create_fileuuidmap(repo_id, parent_dir, file_name, False).uuid.hex
sql = f"SELECT * FROM `{EX_PROPS_TABLE}` WHERE `UUID`='{file_uuid}'"
result = seatable_api.query(sql) result = seatable_api.query(sql)
results = result['results'] results = result['results']
if not results: if not results:
return api_error(status.HTTP_404_NOT_FOUND, 'The props of the file not found') return api_error(status.HTTP_404_NOT_FOUND, 'The props of the file or folder not found')
row_id = results[0]['_id'] row_id = results[0]['_id']
## update props row ## update props row
props_data = {col_name: value for col_name, value in props_data.items() if col_name in EX_EDITABLE_COLUMNS} props_data = {col_name: value for col_name, value in props_data.items() if col_name in EX_EDITABLE_COLUMNS}
@@ -256,7 +259,7 @@ class ExtendedPropertiesView(APIView):
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error') return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error')
## query ## query
sql = f"SELECT * FROM {EX_PROPS_TABLE} WHERE `UUID`='{file_uuid}'" sql = f"SELECT * FROM `{EX_PROPS_TABLE}` WHERE `Repo ID`='{repo_id}' AND `Path`='{path}'"
try: try:
result = seatable_api.query(sql) result = seatable_api.query(sql)
except Exception as e: except Exception as e:
@@ -284,9 +287,9 @@ class ExtendedPropertiesView(APIView):
repo = seafile_api.get_repo(repo_id) repo = seafile_api.get_repo(repo_id)
if not repo: if not repo:
return api_error(status.HTTP_404_NOT_FOUND, 'Library not found') return api_error(status.HTTP_404_NOT_FOUND, 'Library not found')
file_id = seafile_api.get_file_id_by_path(repo_id, path) dirent = seafile_api.get_dirent_by_path(repo_id, path)
if not file_id: if not dirent:
return api_error(status.HTTP_404_NOT_FOUND, 'File %s not found' % path) return api_error(status.HTTP_404_NOT_FOUND, 'File or folder %s not found' % path)
# permission check # permission check
if not parse_repo_perm(check_folder_permission(request, repo_id, parent_dir)).can_edit_on_web: if not parse_repo_perm(check_folder_permission(request, repo_id, parent_dir)).can_edit_on_web:
@@ -306,9 +309,7 @@ class ExtendedPropertiesView(APIView):
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error') return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error')
if error_msg: if error_msg:
return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg) return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg)
file_name = os.path.basename(path) sql = f"DELETE FROM `{EX_PROPS_TABLE}` WHERE `Repo ID`='{repo_id}' AND `Path`='{path}'"
file_uuid = FileUUIDMap.objects.get_or_create_fileuuidmap(repo_id, parent_dir, file_name, False).uuid.hex
sql = f"DELETE FROM `{EX_PROPS_TABLE}` WHERE `UUID`='{file_uuid}'"
try: try:
seatable_api.query(sql) seatable_api.query(sql)
except Exception as e: except Exception as e: