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:
@@ -17,7 +17,7 @@ class ExtraAttributesDialog extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { direntDetail } = props;
|
||||
const { direntDetail, direntType } = props;
|
||||
this.state = {
|
||||
animationEnd: false,
|
||||
isLoading: true,
|
||||
@@ -26,8 +26,12 @@ class ExtraAttributesDialog extends Component {
|
||||
columns: [],
|
||||
errorMsg: '',
|
||||
};
|
||||
const direntDetailId = direntDetail.id;
|
||||
if (direntType === 'dir') {
|
||||
this.isEmptyFile = false;
|
||||
} else {
|
||||
const direntDetailId = direntDetail?.id || '';
|
||||
this.isEmptyFile = direntDetailId === '0'.repeat(direntDetailId.length);
|
||||
}
|
||||
this.isExist = false;
|
||||
this.modalRef = React.createRef();
|
||||
}
|
||||
@@ -243,6 +247,7 @@ class ExtraAttributesDialog extends Component {
|
||||
ExtraAttributesDialog.propTypes = {
|
||||
repoID: PropTypes.string,
|
||||
filePath: PropTypes.string,
|
||||
direntType: PropTypes.string,
|
||||
direntDetail: PropTypes.object,
|
||||
onToggle: PropTypes.func,
|
||||
};
|
||||
|
@@ -63,10 +63,9 @@ class DetailListView extends React.Component {
|
||||
this.setState({ isShowExtraAttributes: !this.state.isShowExtraAttributes });
|
||||
}
|
||||
|
||||
render() {
|
||||
let { direntType, direntDetail, fileTagList } = this.props;
|
||||
let position = this.getDirentPosition();
|
||||
let direntPath = this.getDirentPath();
|
||||
renderTags = () => {
|
||||
const { direntType, direntDetail, fileTagList } = this.props;
|
||||
const position = this.getDirentPosition();
|
||||
if (direntType === 'dir') {
|
||||
return (
|
||||
<table className="table-thead-hidden">
|
||||
@@ -76,12 +75,20 @@ class DetailListView extends React.Component {
|
||||
<tbody>
|
||||
<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>
|
||||
{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>
|
||||
</table>
|
||||
);
|
||||
} else {
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
<table className="table-thead-hidden">
|
||||
<thead>
|
||||
<tr><th width="35%"></th><th width="65%"></th></tr>
|
||||
@@ -117,6 +124,16 @@ class DetailListView extends React.Component {
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { direntType, direntDetail, fileTagList } = this.props;
|
||||
const direntPath = this.getDirentPath();
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{this.renderTags()}
|
||||
{this.state.isEditFileTagShow &&
|
||||
<ModalPortal>
|
||||
<EditFileTagDialog
|
||||
@@ -132,6 +149,7 @@ class DetailListView extends React.Component {
|
||||
<ExtraAttributesDialog
|
||||
repoID={this.props.repoID}
|
||||
filePath={direntPath}
|
||||
direntType={direntType}
|
||||
direntDetail={direntDetail}
|
||||
onToggle={this.toggleExtraAttributesDialog}
|
||||
/>
|
||||
@@ -139,7 +157,6 @@ class DetailListView extends React.Component {
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DetailListView.defaultProps = {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import stat
|
||||
from datetime import datetime
|
||||
|
||||
from rest_framework import status
|
||||
@@ -51,7 +52,7 @@ class ExtendedPropertiesView(APIView):
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, 'path invalid')
|
||||
path = normalize_file_path(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')
|
||||
if not props_data_str or not isinstance(props_data_str, str):
|
||||
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')
|
||||
dirent = seafile_api.get_dirent_by_path(repo_id, path)
|
||||
if not dirent:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'File %s not found' % path)
|
||||
if dirent.obj_id == EMPTY_SHA1:
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, 'File %s is empty' % path)
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'File or folder %s not found' % path)
|
||||
if not stat.S_ISDIR(dirent.mode) and dirent.obj_id == EMPTY_SHA1:
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, 'File or folder %s is empty' % path)
|
||||
|
||||
# permission check
|
||||
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:
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg)
|
||||
## check existed props row
|
||||
file_uuid = FileUUIDMap.objects.get_or_create_fileuuidmap(repo_id, parent_dir, file_name, False).uuid.hex
|
||||
sql = f"SELECT COUNT(1) as `count` FROM `{EX_PROPS_TABLE}` WHERE `UUID`='{file_uuid}'"
|
||||
file_uuid = None
|
||||
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)
|
||||
count = result['results'][0]['count']
|
||||
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.update({
|
||||
'Repo ID': repo_id,
|
||||
'File': file_name,
|
||||
'File': dirent_name,
|
||||
'Path': path,
|
||||
'UUID': file_uuid,
|
||||
'创建日期': str(datetime.fromtimestamp(dirent.mtime)),
|
||||
@@ -113,7 +116,7 @@ class ExtendedPropertiesView(APIView):
|
||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error')
|
||||
|
||||
## 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:
|
||||
result = seatable_api.query(sql)
|
||||
except Exception as e:
|
||||
@@ -141,9 +144,9 @@ class ExtendedPropertiesView(APIView):
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
if not repo:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'Library not found')
|
||||
file_id = seafile_api.get_file_id_by_path(repo_id, path)
|
||||
if not file_id:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'File %s not found' % path)
|
||||
dirent = seafile_api.get_dirent_by_path(repo_id, path)
|
||||
if not dirent:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'File or folder %s not found' % path)
|
||||
|
||||
# permission check
|
||||
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:
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg)
|
||||
## query
|
||||
file_name = os.path.basename(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}'"
|
||||
dirent_name = os.path.basename(path)
|
||||
file_uuid = None
|
||||
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:
|
||||
result = seatable_api.query(sql)
|
||||
except Exception as e:
|
||||
@@ -178,7 +183,7 @@ class ExtendedPropertiesView(APIView):
|
||||
else:
|
||||
row = {
|
||||
'Repo ID': repo_id,
|
||||
'File': file_name,
|
||||
'File': dirent_name,
|
||||
'Path': path,
|
||||
'UUID': file_uuid
|
||||
}
|
||||
@@ -216,9 +221,9 @@ class ExtendedPropertiesView(APIView):
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
if not repo:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'Library not found')
|
||||
file_id = seafile_api.get_file_id_by_path(repo_id, path)
|
||||
if not file_id:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'File %s not found' % path)
|
||||
dirent = seafile_api.get_dirent_by_path(repo_id, path)
|
||||
if not dirent:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'File or folder %s not found' % path)
|
||||
|
||||
# permission check
|
||||
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:
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg)
|
||||
## check existed props row
|
||||
file_name = os.path.basename(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}'"
|
||||
sql = f"SELECT * FROM `{EX_PROPS_TABLE}` WHERE `Repo ID`='{repo_id}' AND `Path`='{path}'"
|
||||
result = seatable_api.query(sql)
|
||||
results = result['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']
|
||||
## update props row
|
||||
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')
|
||||
|
||||
## 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:
|
||||
result = seatable_api.query(sql)
|
||||
except Exception as e:
|
||||
@@ -284,9 +287,9 @@ class ExtendedPropertiesView(APIView):
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
if not repo:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'Library not found')
|
||||
file_id = seafile_api.get_file_id_by_path(repo_id, path)
|
||||
if not file_id:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'File %s not found' % path)
|
||||
dirent = seafile_api.get_dirent_by_path(repo_id, path)
|
||||
if not dirent:
|
||||
return api_error(status.HTTP_404_NOT_FOUND, 'File or folder %s not found' % path)
|
||||
|
||||
# permission check
|
||||
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')
|
||||
if error_msg:
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Props table invalid: %s' % error_msg)
|
||||
file_name = os.path.basename(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}'"
|
||||
sql = f"DELETE FROM `{EX_PROPS_TABLE}` WHERE `Repo ID`='{repo_id}' AND `Path`='{path}'"
|
||||
try:
|
||||
seatable_api.query(sql)
|
||||
except Exception as e:
|
||||
|
Reference in New Issue
Block a user