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) {
|
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,
|
||||||
};
|
};
|
||||||
|
@@ -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: [],
|
||||||
|
@@ -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:
|
||||||
|
Reference in New Issue
Block a user