Skip to content

Commit

Permalink
update repo trash (#6148)
Browse files Browse the repository at this point in the history
* update repo trash

* update code

* select trash

* update

* update

* merge clean trash

* fix-uni-test-and-code-optimize

* Update mysql.sql

* code-optimize

* update select

* update sql

* update UI

* change trash dialog style

* optimize code

* fix code format

* Update repo_trash.py

* update

* add clean trash Command

* update

* optimize code

* support page

* support frontend page

* update

* Update __init__.py

* Update clean_repo_trash.py

* Update clean_repo_trash.py

* Update clean_repo_trash.py

* Update trash-dialog.js

* Update clean_repo_trash.py

* set default by 90

* Update clean_repo_trash.py

* update

---------

Co-authored-by: 孙永强 <[email protected]>
Co-authored-by: r350178982 <[email protected]>
Co-authored-by: Michael An <[email protected]>
  • Loading branch information
4 people authored Jul 18, 2024
1 parent cf7272c commit 0981a0d
Show file tree
Hide file tree
Showing 16 changed files with 714 additions and 15 deletions.
432 changes: 432 additions & 0 deletions frontend/src/components/dialog/trash-dialog.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions frontend/src/components/dir-view-mode/dir-column-nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ class DirColumnNav extends React.Component {
<DirOthers
repoID={this.props.repoID}
userPerm={this.props.userPerm}
currentRepoInfo={this.props.currentRepoInfo}
/>
</>
);
Expand Down
22 changes: 17 additions & 5 deletions frontend/src/components/dir-view-mode/dir-others.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import React from 'react';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { gettext, siteRoot } from '../../utils/constants';
import TreeSection from '../tree-section';
import TrashDialog from '../dialog/trash-dialog';

const DirOthers = ({ userPerm, repoID }) => {

const DirOthers = ({ userPerm, repoID, currentRepoInfo }) => {
const [showTrashDialog, setShowTrashDialog] = useState(false);
let trashUrl = null;
const historyUrl = siteRoot + 'repo/history/' + repoID + '/';
if (userPerm === 'rw') {
trashUrl = siteRoot + 'repo/' + repoID + '/trash/';
}

const toggleTrashDialog = () => {
setShowTrashDialog(!showTrashDialog);
};
return (
<TreeSection title={gettext('Others')} className="dir-others">
{trashUrl &&
<div className='tree-node-inner text-nowrap' title={gettext('Trash')} onClick={() => location.href = trashUrl}>
<div className='tree-node-inner text-nowrap' title={gettext('Trash')} onClick={toggleTrashDialog}>
<div className="tree-node-text">{gettext('Trash')}</div>
<div className="left-icon">
<div className="tree-node-icon">
Expand All @@ -31,13 +34,22 @@ const DirOthers = ({ userPerm, repoID }) => {
</div>
</div>
</div>
{showTrashDialog && (
<TrashDialog
repoID={repoID}
currentRepoInfo={currentRepoInfo}
showTrashDialog={showTrashDialog}
toggleTrashDialog={toggleTrashDialog}
/>
)}
</TreeSection>
);
};

DirOthers.propTypes = {
userPerm: PropTypes.string,
repoID: PropTypes.string,
currentRepoInfo: PropTypes.object.isRequired,
};

export default DirOthers;
44 changes: 44 additions & 0 deletions frontend/src/css/trash-dialog.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
.trash-dialog {
max-width: 1100px;
}

.trash-dialog .modal-header {
align-items: center;
}

.trash-dialog .modal-header .trash-dialog-old-page {
margin-left: auto;
}

.trash-dialog .modal-header .trash-dialog-close-icon {
color: #000;
opacity: 0.5;
font-weight: 700;
cursor: pointer;
}

.trash-dialog .modal-header .trash-dialog-close-icon:hover {
opacity: 0.75;
}

.trash-dialog .modal-header .clean {
height: 30px;
line-height: 28px;
padding: 0 0.5rem;
}

.trash-dialog .modal-body {
height: 500px;
overflow-y: auto;
}

.trash-dialog .modal-body .more {
background: #efefef;
border: 0;
color: #777;
}

.trash-dialog .modal-body .more:hover {
color: #000;
background: #dfdfdf;
}
6 changes: 3 additions & 3 deletions frontend/src/repo-folder-trash.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const {
repoID,
repoFolderName,
path,
enableClean,
enableUserCleanTrash,
isRepoAdmin
} = window.app.pageOptions;

Expand All @@ -35,7 +35,7 @@ class RepoFolderTrash extends React.Component {
items: [],
scanStat: null,
more: false,
isCleanTrashDialogOpen: false
isCleanTrashDialogOpen: false,
};
}

Expand Down Expand Up @@ -204,7 +204,7 @@ class RepoFolderTrash extends React.Component {
</a>
<div className="d-flex justify-content-between align-items-center op-bar">
<p className="m-0 text-truncate d-flex"><span className="mr-1">{gettext('Current path: ')}</span>{showFolder ? this.renderFolderPath() : <span className="text-truncate" title={repoFolderName}>{repoFolderName}</span>}</p>
{(path == '/' && enableClean && !showFolder && isRepoAdmin) &&
{(path == '/' && enableUserCleanTrash && !showFolder && isRepoAdmin) &&
<button className="btn btn-secondary clean flex-shrink-0 ml-4" onClick={this.cleanTrash}>{gettext('Clean')}</button>
}
</div>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const maxFileName = window.app.pageOptions.maxFileName;
export const canPublishRepo = window.app.pageOptions.canPublishRepo;
export const enableEncryptedLibrary = window.app.pageOptions.enableEncryptedLibrary;
export const enableRepoHistorySetting = window.app.pageOptions.enableRepoHistorySetting;
export const enableUserCleanTrash = window.app.pageOptions.enableUserCleanTrash;
export const isSystemStaff = window.app.pageOptions.isSystemStaff;
export const thumbnailSizeForOriginal = window.app.pageOptions.thumbnailSizeForOriginal;
export const repoPasswordMinLength = window.app.pageOptions.repoPasswordMinLength;
Expand Down
51 changes: 51 additions & 0 deletions frontend/src/utils/repo-trash-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import axios from 'axios';
import cookie from 'react-cookies';
import { siteRoot } from './constants';

class RepotrashAPI {

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;
}

getRepoFolderTrash2(repoID, page, per_page) {
const url = this.server + '/api/v2.1/repos/' + repoID + '/trash2/';
let params = {
page: page || 1,
per_page: per_page
};
return this.req.get(url, {params: params});
}
}

let repotrashAPI = new RepotrashAPI();
let xcsrfHeaders = cookie.load('sfcsrftoken');
repotrashAPI.initForSeahubUsage({ siteRoot, xcsrfHeaders });

export { repotrashAPI };
90 changes: 89 additions & 1 deletion seahub/api2/endpoints/repo_trash.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Copyright (c) 2012-2016 Seafile Ltd.
import stat
import logging
import os
from datetime import datetime

from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
Expand All @@ -13,6 +15,7 @@
from seahub.api2.utils import api_error

from seahub.signals import clean_up_repo_trash
from seahub.utils import get_trash_records
from seahub.utils.timeutils import timestamp_to_isoformat_timestr
from seahub.utils.repo import get_repo_owner, is_repo_admin
from seahub.views import check_folder_permission
Expand All @@ -24,7 +27,7 @@
from constance import config

logger = logging.getLogger(__name__)

SHOW_REPO_TRASH_DAYS = 90

class RepoTrash(APIView):

Expand Down Expand Up @@ -303,3 +306,88 @@ def post(self, request, repo_id):
})

return Response(result)


class RepoTrash2(APIView):

authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated, )
throttle_classes = (UserRateThrottle, )

def get_item_info(self, trash_item):

item_info = {
'parent_dir': '/' if trash_item.path == '/' else trash_item.path,
'obj_name': trash_item.obj_name,
'deleted_time': timestamp_to_isoformat_timestr(int(trash_item.delete_time.timestamp())),
'commit_id': trash_item.commit_id,
}

if trash_item.obj_type == 'dir':
is_dir = True
else:
is_dir = False

item_info['is_dir'] = is_dir
item_info['size'] = trash_item.size if not is_dir else ''
item_info['obj_id'] = trash_item.obj_id if not is_dir else ''

return item_info

def get(self, request, repo_id):
""" Return deleted files/dirs of a repo/folder
Permission checking:
1. all authenticated user can perform this action.
"""

path = '/'
# 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)

try:
current_page = int(request.GET.get('page', '1'))
per_page = int(request.GET.get('per_page', '100'))
except ValueError:
current_page = 1
per_page = 100
start = (current_page - 1) * per_page
limit = per_page
try:
dir_id = seafile_api.get_dir_id_by_path(repo_id, path)
except SearpcError as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

if not dir_id:
error_msg = 'Folder %s not found.' % path
return api_error(status.HTTP_404_NOT_FOUND, error_msg)

# permission check
if check_folder_permission(request, repo_id, path) is None:
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)

try:
deleted_entries, total_count = get_trash_records(repo_id, SHOW_REPO_TRASH_DAYS, start, limit)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

items = []
if len(deleted_entries) >= 1:
for item in deleted_entries:
item_info = self.get_item_info(item)
items.append(item_info)

result = {
'items': items,
'total_count': total_count
}

return Response(result)
41 changes: 41 additions & 0 deletions seahub/base/management/commands/clean_repo_trash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import logging
from datetime import datetime
from seahub.utils import SeafEventsSession
from seafevents import seafevents_api
from django.core.management.base import BaseCommand


logger = logging.getLogger(__name__)

class Command(BaseCommand):
help = 'Clear repo trash within the specified time'
label = 'clean_repo_trash'

def print_msg(self, msg):
self.stdout.write('[%s] %s\n' % (datetime.now(), msg))

def add_arguments(self, parser):
parser.add_argument('--keep-days', help='keep days', type=int, default=90)

def handle(self, *args, **options):
days = options.get('keep_days')
if days < 0:
self.print_msg('keep-days cannot be set to nagative number')
return
logger.info('Start clean repo trash...')
self.print_msg('Start clean repo trash...')
self.do_action(days)
self.print_msg('Finish clean repo trash.\n')
logger.info('Finish clean repo trash.\n')

def do_action(self, days):
try:
session = SeafEventsSession()
seafevents_api.clean_up_all_repo_trash(session, days)
except Exception as e:
logger.debug('Clean up repo trash error: %s' % e)
self.print_msg('Clean up repo trash error: %s' % e)
return

logger.info('Successfully cleared repo trash older than %s days' % days)
self.print_msg('Successfully cleared repo trash older than %s days' % days)
7 changes: 6 additions & 1 deletion seahub/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,12 @@ def clean_up_repo_trash_cb(sender, **kwargs):

from .utils import SeafEventsSession
session = SeafEventsSession()
seafevents_api.save_user_activity(session, record)
try:
seafevents_api.save_user_activity(session, record)
seafevents_api.clean_up_repo_trash(session, repo_id, days)
except Exception as e:
logger.error(e)

session.close()

def repo_restored_cb(sender, **kwargs):
Expand Down
1 change: 1 addition & 0 deletions seahub/templates/base_for_react.html
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
canPublishRepo: {% if user.permissions.can_publish_repo %} true {% else %} false {% endif %},
enableEncryptedLibrary: {% if enable_encrypted_library %} true {% else %} false {% endif %},
enableRepoHistorySetting: {% if enable_repo_history_setting %} true {% else %} false {% endif %},
enableUserCleanTrash: {% if enable_user_clean_trash %} true {% else %} false {% endif %},
isSystemStaff: {% if request.user.is_staff %} true {% else %} false {% endif %},
thumbnailSizeForOriginal: {{ thumbnail_size_for_original }},
repoPasswordMinLength: {{repo_password_min_length}},
Expand Down
2 changes: 1 addition & 1 deletion seahub/templates/repo_folder_trash_react.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
repoID: '{{repo.id}}',
repoFolderName: '{{repo_folder_name|escapejs}}',
path: '{{path|escapejs}}',
enableClean: {% if enable_clean %} true {% else %} false {% endif %},
enableUserCleanTrash: {% if enable_user_clean_trash %} true {% else %} false {% endif %},
isRepoAdmin: {% if is_repo_admin %} true {% else %} false {% endif %}
};
</script>
Expand Down
3 changes: 2 additions & 1 deletion seahub/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
from seahub.api2.endpoints.dir import DirView, DirDetailView
from seahub.api2.endpoints.file_tag import FileTagView
from seahub.api2.endpoints.file_tag import FileTagsView
from seahub.api2.endpoints.repo_trash import RepoTrash, RepoTrashRevertDirents
from seahub.api2.endpoints.repo_trash import RepoTrash, RepoTrashRevertDirents, RepoTrash2
from seahub.api2.endpoints.repo_commit import RepoCommitView
from seahub.api2.endpoints.repo_commit_dir import RepoCommitDirView
from seahub.api2.endpoints.repo_commit_revert import RepoCommitRevertView
Expand Down Expand Up @@ -430,6 +430,7 @@
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/commits/(?P<commit_id>[0-9a-f]{40})/revert/$', RepoCommitRevertView.as_view(), name='api-v2.1-repo-commit-revert'),
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/dir/detail/$', DirDetailView.as_view(), name='api-v2.1-dir-detail-view'),
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/trash/$', RepoTrash.as_view(), name='api-v2.1-repo-trash'),
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/trash2/$', RepoTrash2.as_view(), name='api-v2.1-repo-trash2'),
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/trash/revert-dirents/$', RepoTrashRevertDirents.as_view(), name='api-v2.1-repo-trash-revert-dirents'),
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/history/$', RepoHistory.as_view(), name='api-v2.1-repo-history'),
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/set-password/$', RepoSetPassword.as_view(), name="api-v2.1-repo-set-password"),
Expand Down
Loading

0 comments on commit 0981a0d

Please sign in to comment.