mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-12 13:24:52 +00:00
Org export log (#6652)
* org admin export log * optimize code * optimize code * optimize code * update * update code * update --------- Co-authored-by: 孙永强 <11704063+s-yongqiang@user.noreply.gitee.com> Co-authored-by: r350178982 <32759763+r350178982@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,158 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, FormGroup, Label, Input, Alert } from 'reactstrap';
|
||||||
|
import { gettext, siteRoot, orgID } from '../../utils/constants';
|
||||||
|
import { orgAdminAPI } from '../../utils/org-admin-api';
|
||||||
|
import { userAPI } from '../../utils/user-api';
|
||||||
|
import toaster from '../../components/toast';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
class OrgLogsExportExcelDialog extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
startDateStr: '',
|
||||||
|
endDateStr: '',
|
||||||
|
errMsg: '',
|
||||||
|
taskId: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadExcel = () => {
|
||||||
|
if (!this.isValidDateStr()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (this.props.logType) {
|
||||||
|
case 'fileaudit':
|
||||||
|
this.orgAdminExportLogs('fileaudit');
|
||||||
|
break;
|
||||||
|
case 'file-update':
|
||||||
|
this.orgAdminExportLogs('fileupdate');
|
||||||
|
break;
|
||||||
|
case 'perm-audit':
|
||||||
|
this.orgAdminExportLogs('permaudit');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
orgAdminExportLogs = (logType) => {
|
||||||
|
let { startDateStr, endDateStr } = this.state;
|
||||||
|
let task_id = '';
|
||||||
|
orgAdminAPI.orgAdminExportLogsExcel(orgID, startDateStr, endDateStr, logType).then(res => {
|
||||||
|
task_id = res.data.task_id;
|
||||||
|
this.setState({
|
||||||
|
taskId: task_id
|
||||||
|
});
|
||||||
|
this.props.toggle();
|
||||||
|
return userAPI.queryIOStatus(task_id);
|
||||||
|
}).then(res => {
|
||||||
|
if (res.data.is_finished === true) {
|
||||||
|
location.href = siteRoot + 'api/v2.1/org/admin/log/export-excel/?task_id=' + task_id + '&log_type=' + logType;
|
||||||
|
} else {
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
userAPI.queryIOStatus(task_id).then(res => {
|
||||||
|
if (res.data.is_finished === true) {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
location.href = siteRoot + 'api/v2.1/org/admin/log/export-excel/?task_id=' + task_id + '&log_type=' + logType;
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
toaster.danger(gettext('Failed to export. Please check whether the size of table attachments exceeds the limit.'));
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
this.props.toggle();
|
||||||
|
if (error.response && error.response.status === 500) {
|
||||||
|
const error_msg = error.response.data ? error.response.data['error_msg'] : null;
|
||||||
|
if (error_msg && error_msg !== 'Internal Server Error') {
|
||||||
|
toaster.danger(error_msg);
|
||||||
|
} else {
|
||||||
|
toaster.danger(gettext('Internal Server Error'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
isValidDateStr = () => {
|
||||||
|
let { startDateStr, endDateStr } = this.state;
|
||||||
|
if (moment(startDateStr, 'YYYY-MM-DD', true).isValid() &&
|
||||||
|
moment(endDateStr, 'YYYY-MM-DD', true).isValid() &&
|
||||||
|
moment(startDateStr).isBefore(endDateStr)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
errMsg: gettext('Date Invalid.')
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleStartChange = (e) => {
|
||||||
|
const startDateStr = e.target.value.trim();
|
||||||
|
this.setState({
|
||||||
|
startDateStr: startDateStr,
|
||||||
|
errMsg: ''
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleEndChange = (e) => {
|
||||||
|
const endDateStr = e.target.value.trim();
|
||||||
|
this.setState({
|
||||||
|
endDateStr: endDateStr,
|
||||||
|
errMsg: '',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Modal isOpen={true} toggle={this.props.toggle} autoFocus={false}>
|
||||||
|
<ModalHeader toggle={this.props.toggle}>{gettext('Choose date')}</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<FormGroup>
|
||||||
|
<Label>{gettext('Start date')}</Label>
|
||||||
|
<Input
|
||||||
|
value={this.state.startDateStr}
|
||||||
|
onChange={this.handleStartChange}
|
||||||
|
placeholder='yyyy-mm-dd'
|
||||||
|
autoFocus={true}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup>
|
||||||
|
<Label>{gettext('End date')}</Label>
|
||||||
|
<Input
|
||||||
|
value={this.state.endDateStr}
|
||||||
|
onChange={this.handleEndChange}
|
||||||
|
placeholder='yyyy-mm-dd'
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
{this.state.errMsg &&
|
||||||
|
<Alert className="mt-2" color="danger">
|
||||||
|
{gettext(this.state.errMsg)}
|
||||||
|
</Alert>
|
||||||
|
}
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button color="secondary" onClick={this.props.toggle}>{gettext('Cancel')}</Button>
|
||||||
|
<Button color="primary" onClick={this.downloadExcel}>{gettext('Submit')}</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
toggle: PropTypes.func.isRequired,
|
||||||
|
logType: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
OrgLogsExportExcelDialog.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default OrgLogsExportExcelDialog;
|
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, FormGroup, Label, Input, Alert } from 'reactstrap';
|
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, FormGroup, Label, Input, Alert } from 'reactstrap';
|
||||||
import { gettext, siteRoot } from '../../../utils/constants';
|
import { gettext, siteRoot } from '../../../utils/constants';
|
||||||
import { systemAdminAPI } from '../../../utils/system-admin-api';
|
import { systemAdminAPI } from '../../../utils/system-admin-api';
|
||||||
|
import { userAPI } from '../../../utils/user-api';
|
||||||
import toaster from '../../../components/toast';
|
import toaster from '../../../components/toast';
|
||||||
import { Utils } from '../../../utils/utils';
|
import { Utils } from '../../../utils/utils';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
@@ -49,23 +50,20 @@ class LogsExportExcelDialog extends React.Component {
|
|||||||
taskId: task_id
|
taskId: task_id
|
||||||
});
|
});
|
||||||
this.props.toggle();
|
this.props.toggle();
|
||||||
return systemAdminAPI.queryAsyncOperationExportExcel(task_id);
|
return userAPI.queryIOStatus(task_id);
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
if (res.data.is_finished === true) {
|
if (res.data.is_finished === true) {
|
||||||
location.href = siteRoot + 'sys/log/export-excel/?task_id=' + task_id + '&log_type=' + logType;
|
location.href = siteRoot + 'sys/log/export-excel/?task_id=' + task_id + '&log_type=' + logType;
|
||||||
} else {
|
} else {
|
||||||
this.timer = setInterval(() => {
|
this.timer = setInterval(() => {
|
||||||
systemAdminAPI.queryAsyncOperationExportExcel(task_id).then(res => {
|
userAPI.queryIOStatus(task_id).then(res => {
|
||||||
if (res.data.is_finished === true) {
|
if (res.data.is_finished === true) {
|
||||||
this.setState({ isFinished: true });
|
|
||||||
clearInterval(this.timer);
|
clearInterval(this.timer);
|
||||||
location.href = siteRoot + 'sys/log/export-excel/?task_id=' + task_id + '&log_type=' + logType;
|
location.href = siteRoot + 'sys/log/export-excel/?task_id=' + task_id + '&log_type=' + logType;
|
||||||
}
|
}
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
if (this.state.isFinished === false) {
|
|
||||||
clearInterval(this.timer);
|
clearInterval(this.timer);
|
||||||
toaster.danger(gettext('Failed to export. Please check whether the size of table attachments exceeds the limit.'));
|
toaster.danger(gettext('Failed to export. Please check whether the size of table attachments exceeds the limit.'));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
@@ -73,7 +73,14 @@ class Org extends React.Component {
|
|||||||
if (location.href.indexOf(`${siteRoot}org/departmentadmin`) != -1) {
|
if (location.href.indexOf(`${siteRoot}org/departmentadmin`) != -1) {
|
||||||
currentTab = 'departmentadmin';
|
currentTab = 'departmentadmin';
|
||||||
}
|
}
|
||||||
this.setState({ currentTab: currentTab });
|
if (location.href.indexOf(`${siteRoot}org/logadmin/`) != -1) {
|
||||||
|
if (currentTab === 'logadmin') {
|
||||||
|
currentTab = 'fileaudit';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
currentTab: currentTab
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onCloseSidePanel = () => {
|
onCloseSidePanel = () => {
|
||||||
|
@@ -3,28 +3,53 @@ import PropTypes from 'prop-types';
|
|||||||
import { Link } from '@gatsbyjs/reach-router';
|
import { Link } from '@gatsbyjs/reach-router';
|
||||||
import { siteRoot, gettext } from '../../utils/constants';
|
import { siteRoot, gettext } from '../../utils/constants';
|
||||||
import MainPanelTopbar from './main-panel-topbar';
|
import MainPanelTopbar from './main-panel-topbar';
|
||||||
|
import { Button } from 'reactstrap';
|
||||||
|
import ModalPortal from '../../components/modal-portal';
|
||||||
|
import OrgLogsExportExcelDialog from '../../components/dialog/org-admin-logs-export-excel-dialog';
|
||||||
|
|
||||||
class OrgLogs extends Component {
|
class OrgLogs extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isExportExcelDialogOpen: false,
|
||||||
|
logType: '',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
let href = window.location.href.split('/');
|
||||||
|
let logtype = href[href.length - 2];
|
||||||
|
if (logtype === 'logadmin') {
|
||||||
|
logtype = 'fileaudit';
|
||||||
|
}
|
||||||
|
this.setState({ logType: logtype });
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleExportExcelDialog = () => {
|
||||||
|
this.setState({ isExportExcelDialogOpen: !this.state.isExportExcelDialogOpen });
|
||||||
|
};
|
||||||
tabItemClick = (param) => {
|
tabItemClick = (param) => {
|
||||||
|
this.setState({
|
||||||
|
logType: param
|
||||||
|
});
|
||||||
this.props.tabItemClick(param);
|
this.props.tabItemClick(param);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { isExportExcelDialogOpen, logType } = this.state;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<MainPanelTopbar/>
|
<MainPanelTopbar>
|
||||||
|
<Button className="btn btn-secondary operation-item" onClick={this.toggleExportExcelDialog}>{gettext('Export Excel')}</Button>
|
||||||
|
</MainPanelTopbar>
|
||||||
<div className="main-panel-center flex-row">
|
<div className="main-panel-center flex-row">
|
||||||
<div className="cur-view-container">
|
<div className="cur-view-container h-100">
|
||||||
<div className="cur-view-path org-user-nav">
|
<div className="cur-view-path org-user-nav">
|
||||||
<ul className="nav">
|
<ul className="nav">
|
||||||
<li className="nav-item" onClick={() => this.tabItemClick('logadmin')}>
|
<li className="nav-item" onClick={() => this.tabItemClick('fileaudit')}>
|
||||||
<Link
|
<Link
|
||||||
className={`nav-link ${this.props.currentTab === 'logadmin' ? 'active' : ''}`}
|
className={`nav-link ${this.props.currentTab === 'fileaudit' ? 'active' : ''}`}
|
||||||
to={siteRoot + 'org/logadmin/'} title={gettext('File Access')}>{gettext('File Access')}
|
to={siteRoot + 'org/logadmin/'} title={gettext('File Access')}>{gettext('File Access')}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
@@ -42,9 +67,19 @@ class OrgLogs extends Component {
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="h-100 o-auto">
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
{isExportExcelDialogOpen &&
|
||||||
|
<ModalPortal>
|
||||||
|
<OrgLogsExportExcelDialog
|
||||||
|
logType={logType}
|
||||||
|
toggle={this.toggleExportExcelDialog}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -95,8 +95,8 @@ class SidePanel extends React.Component {
|
|||||||
<span className="nav-text">{gettext('Links')}</span>
|
<span className="nav-text">{gettext('Links')}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className={`nav-item ${this.getActiveClass('logadmin') || this.getActiveClass('file-update') || this.getActiveClass('perm-audit')}`}>
|
<li className={`nav-item ${this.getActiveClass('fileaudit') || this.getActiveClass('file-update') || this.getActiveClass('perm-audit')}`}>
|
||||||
<Link className={`nav-link ellipsis ${this.getActiveClass('logadmin') || this.getActiveClass('file-update') || this.getActiveClass('perm-audit')}`} to={siteRoot + 'org/logadmin/'} onClick={() => this.tabItemClick('logadmin')} >
|
<Link className={`nav-link ellipsis ${this.getActiveClass('fileaudit') || this.getActiveClass('file-update') || this.getActiveClass('perm-audit')}`} to={siteRoot + 'org/logadmin/'} onClick={() => this.tabItemClick('fileaudit')} >
|
||||||
<span className="sf2-icon-clock"></span>
|
<span className="sf2-icon-clock"></span>
|
||||||
<span className="nav-text">{gettext('Logs')}</span>
|
<span className="nav-text">{gettext('Logs')}</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
@@ -49,6 +49,16 @@ class OrgAdminAPI {
|
|||||||
return this.req.post(url);
|
return this.req.post(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orgAdminExportLogsExcel(orgID, start, end, logType) {
|
||||||
|
const url = this.server + '/api/v2.1/org/' + orgID + '/admin/logs/export-excel/';
|
||||||
|
const params = {
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
logType: logType
|
||||||
|
};
|
||||||
|
return this.req.get(url, { params: params });
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let orgAdminAPI = new OrgAdminAPI();
|
let orgAdminAPI = new OrgAdminAPI();
|
||||||
|
@@ -76,11 +76,6 @@ class SystemAdminAPI {
|
|||||||
return this.req.get(url, { params: params });
|
return this.req.get(url, { params: params });
|
||||||
}
|
}
|
||||||
|
|
||||||
queryAsyncOperationExportExcel(task_id) {
|
|
||||||
const url = this.server + '/api/v2.1/query-export-status/?task_id=' + task_id;
|
|
||||||
return this.req.get(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
adminGroup2Department(groupID) {
|
adminGroup2Department(groupID) {
|
||||||
const url = this.server + '/api/v2.1/admin/groups/' + groupID + '/group-to-department/';
|
const url = this.server + '/api/v2.1/admin/groups/' + groupID + '/group-to-department/';
|
||||||
return this.req.post(url);
|
return this.req.post(url);
|
||||||
|
@@ -42,6 +42,11 @@ class UserAPI {
|
|||||||
};
|
};
|
||||||
return this.req.post(url, data);
|
return this.req.post(url, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queryIOStatus(task_id) {
|
||||||
|
const url = this.server + '/api/v2.1/query-io-status/?task_id=' + task_id;
|
||||||
|
return this.req.get(url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let userAPI = new UserAPI();
|
let userAPI = new UserAPI();
|
||||||
|
@@ -1,7 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
import logging
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from django.http import FileResponse
|
from django.http import FileResponse
|
||||||
from rest_framework.authentication import SessionAuthentication
|
from rest_framework.authentication import SessionAuthentication
|
||||||
@@ -9,6 +6,7 @@ from rest_framework.permissions import IsAdminUser
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
from rest_framework.decorators import api_view
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
|
|
||||||
from seahub.api2.authentication import TokenAuthentication
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
@@ -39,34 +37,11 @@ class SysLogsExport(APIView):
|
|||||||
return Response(res_data)
|
return Response(res_data)
|
||||||
|
|
||||||
|
|
||||||
class FileLogsExportStatus(APIView):
|
|
||||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
|
||||||
permission_classes = (IsAdminUser, IsProVersion)
|
|
||||||
throttle_classes = (UserRateThrottle,)
|
|
||||||
|
|
||||||
def get(self, request):
|
|
||||||
"""
|
|
||||||
Get task status by task id
|
|
||||||
"""
|
|
||||||
task_id = request.GET.get('task_id', '')
|
|
||||||
if not task_id:
|
|
||||||
error_msg = 'task_id invalid.'
|
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
|
||||||
|
|
||||||
resp = event_export_status(task_id)
|
|
||||||
if resp.status_code == 500:
|
|
||||||
logger.error('query export status error: %s, %s' % (task_id, resp.content))
|
|
||||||
return api_error(500, 'Internal Server Error')
|
|
||||||
if not resp.status_code == 200:
|
|
||||||
return api_error(resp.status_code, resp.content)
|
|
||||||
|
|
||||||
is_finished = json.loads(resp.content)['is_finished']
|
|
||||||
|
|
||||||
return Response({'is_finished': is_finished})
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@sys_staff_required
|
@sys_staff_required
|
||||||
|
@api_view(('GET',))
|
||||||
def sys_log_export_excel(request):
|
def sys_log_export_excel(request):
|
||||||
task_id = request.GET.get('task_id', None)
|
task_id = request.GET.get('task_id', None)
|
||||||
log_type = request.GET.get('log_type', None)
|
log_type = request.GET.get('log_type', None)
|
||||||
|
41
seahub/api2/endpoints/seahub_io.py
Normal file
41
seahub/api2/endpoints/seahub_io.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import logging
|
||||||
|
import json
|
||||||
|
|
||||||
|
from rest_framework.authentication import SessionAuthentication
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
|
from seahub.api2.endpoints.utils import event_export_status
|
||||||
|
from seahub.api2.permissions import IsProVersion
|
||||||
|
from seahub.api2.throttling import UserRateThrottle
|
||||||
|
from seahub.api2.utils import api_error
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class SeahubIOStatus(APIView):
|
||||||
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
|
permission_classes = (IsProVersion,)
|
||||||
|
throttle_classes = (UserRateThrottle,)
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
"""
|
||||||
|
Get task status by task id
|
||||||
|
"""
|
||||||
|
task_id = request.GET.get('task_id', '')
|
||||||
|
if not task_id:
|
||||||
|
error_msg = 'task_id invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
resp = event_export_status(task_id)
|
||||||
|
if resp.status_code == 500:
|
||||||
|
logger.error('query export status error: %s, %s' % (task_id, resp.content))
|
||||||
|
return api_error(500, 'Internal Server Error')
|
||||||
|
if not resp.status_code == 200:
|
||||||
|
return api_error(resp.status_code, resp.content)
|
||||||
|
|
||||||
|
is_finished = json.loads(resp.content)['is_finished']
|
||||||
|
|
||||||
|
return Response({'is_finished': is_finished})
|
@@ -296,13 +296,16 @@ def format_date(start, end):
|
|||||||
return start_timestamp, end_timestamp
|
return start_timestamp, end_timestamp
|
||||||
|
|
||||||
|
|
||||||
def export_logs_to_excel(start, end, log_type):
|
def export_logs_to_excel(start, end, log_type, org_id=None):
|
||||||
start_time, end_time = format_date(start, end)
|
start_time, end_time = format_date(start, end)
|
||||||
payload = {'exp': int(time.time()) + 300, }
|
payload = {'exp': int(time.time()) + 300, }
|
||||||
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
|
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
|
||||||
headers = {"Authorization": "Token %s" % token}
|
headers = {"Authorization": "Token %s" % token}
|
||||||
url = urljoin(SEAFEVENTS_SERVER_URL, '/add-init-export-log-task')
|
if not org_id:
|
||||||
params = {'start_time': start_time, 'end_time': end_time, 'log_type': log_type}
|
url = urljoin(SEAFEVENTS_SERVER_URL, '/add-export-log-task')
|
||||||
|
else:
|
||||||
|
url = urljoin(SEAFEVENTS_SERVER_URL, '/add-org-export-log-task')
|
||||||
|
params = {'start_time': start_time, 'end_time': end_time, 'log_type': log_type, 'org_id': org_id}
|
||||||
resp = requests.get(url, params=params, headers=headers)
|
resp = requests.get(url, params=params, headers=headers)
|
||||||
return json.loads(resp.content)['task_id']
|
return json.loads(resp.content)['task_id']
|
||||||
|
|
||||||
|
@@ -31,6 +31,8 @@ from .api.admin.statistics import OrgFileOperationsView, OrgTotalStorageView, \
|
|||||||
OrgUserTrafficExcelView, OrgUserStorageExcelView
|
OrgUserTrafficExcelView, OrgUserStorageExcelView
|
||||||
from .api.admin.saml_config import OrgSAMLConfigView, OrgVerifyDomain
|
from .api.admin.saml_config import OrgSAMLConfigView, OrgVerifyDomain
|
||||||
|
|
||||||
|
from .org_logs_export import OrgLogsExport, org_log_export_excel
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('<int:org_id>/admin/statistics/file-operations/',
|
path('<int:org_id>/admin/statistics/file-operations/',
|
||||||
@@ -101,5 +103,8 @@ urlpatterns = [
|
|||||||
path('admin/logs/file-update/', OrgAdminLogsFileUpdate.as_view(), name='api-v2.1-org-admin-logs-file-update'),
|
path('admin/logs/file-update/', OrgAdminLogsFileUpdate.as_view(), name='api-v2.1-org-admin-logs-file-update'),
|
||||||
path('admin/logs/repo-permission/', OrgAdminLogsPermAudit.as_view(), name='api-v2.1-org-admin-logs-repo-permission'),
|
path('admin/logs/repo-permission/', OrgAdminLogsPermAudit.as_view(), name='api-v2.1-org-admin-logs-repo-permission'),
|
||||||
path('<int:org_id>/admin/departments/', OrgAdminDepartments.as_view(), name='api-v2.1-org-admin-departments'),
|
path('<int:org_id>/admin/departments/', OrgAdminDepartments.as_view(), name='api-v2.1-org-admin-departments'),
|
||||||
|
path('<int:org_id>/admin/logs/export-excel/', OrgLogsExport.as_view(), name='api-v2.1-org-logs-export-excel'),
|
||||||
|
path('admin/log/export-excel/', org_log_export_excel, name='org_log_export_excel'),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
72
seahub/organizations/org_logs_export.py
Normal file
72
seahub/organizations/org_logs_export.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from shutil import rmtree
|
||||||
|
from django.http import FileResponse
|
||||||
|
from rest_framework.authentication import SessionAuthentication
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.decorators import api_view
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
|
from seahub.api2.endpoints.utils import check_time_period_valid, export_logs_to_excel
|
||||||
|
from seahub.api2.permissions import IsProVersion
|
||||||
|
from seahub.api2.throttling import UserRateThrottle
|
||||||
|
from seahub.api2.utils import api_error
|
||||||
|
from seahub.auth.decorators import login_required
|
||||||
|
from seahub.organizations.api.permissions import IsOrgAdmin
|
||||||
|
from seahub.organizations.decorators import org_staff_required
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class OrgLogsExport(APIView):
|
||||||
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
|
permission_classes = (IsOrgAdmin, IsProVersion)
|
||||||
|
throttle_classes = (UserRateThrottle,)
|
||||||
|
|
||||||
|
def get(self, request, org_id):
|
||||||
|
start = request.GET.get('start', None)
|
||||||
|
end = request.GET.get('end', None)
|
||||||
|
log_type = request.GET.get('logType', None)
|
||||||
|
if not check_time_period_valid(start, end):
|
||||||
|
error_msg = 'Failed to export excel, invalid start or end date.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
task_id = export_logs_to_excel(start, end, log_type, org_id)
|
||||||
|
res_data = {'task_id': task_id}
|
||||||
|
return Response(res_data)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@org_staff_required
|
||||||
|
@api_view(('GET',))
|
||||||
|
def org_log_export_excel(request):
|
||||||
|
task_id = request.GET.get('task_id', None)
|
||||||
|
log_type = request.GET.get('log_type', None)
|
||||||
|
if not task_id:
|
||||||
|
error_msg = 'task_id invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
if log_type == 'fileaudit':
|
||||||
|
excel_name = 'file-access-logs.xlsx'
|
||||||
|
elif log_type == 'fileupdate':
|
||||||
|
excel_name = 'file-update-logs.xlsx'
|
||||||
|
elif log_type == 'permaudit':
|
||||||
|
excel_name = 'perm-audit-logs.xlsx'
|
||||||
|
else:
|
||||||
|
error_msg = 'log_type invalid'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
target_dir = os.path.join('/tmp/seafile_events/', task_id)
|
||||||
|
tmp_excel_path = os.path.join(target_dir, excel_name)
|
||||||
|
if not os.path.isfile(tmp_excel_path):
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, excel_name + ' not found.')
|
||||||
|
response = FileResponse(open(tmp_excel_path, 'rb'), content_type='application/ms-excel', as_attachment=True)
|
||||||
|
try:
|
||||||
|
rmtree(target_dir)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
response['Content-Disposition'] = 'attachment;filename*=UTF-8\'\'' + quote(excel_name)
|
||||||
|
return response
|
@@ -125,7 +125,7 @@ from seahub.api2.endpoints.repo_share_links import RepoShareLinks, RepoShareLink
|
|||||||
from seahub.api2.endpoints.repo_upload_links import RepoUploadLinks, RepoUploadLink
|
from seahub.api2.endpoints.repo_upload_links import RepoUploadLinks, RepoUploadLink
|
||||||
|
|
||||||
# Admin
|
# Admin
|
||||||
from seahub.api2.endpoints.admin.logs_export import SysLogsExport, FileLogsExportStatus, sys_log_export_excel
|
from seahub.api2.endpoints.admin.logs_export import SysLogsExport, sys_log_export_excel
|
||||||
from seahub.api2.endpoints.admin.abuse_reports import AdminAbuseReportsView, AdminAbuseReportView
|
from seahub.api2.endpoints.admin.abuse_reports import AdminAbuseReportsView, AdminAbuseReportView
|
||||||
from seahub.api2.endpoints.admin.revision_tag import AdminTaggedItemsView
|
from seahub.api2.endpoints.admin.revision_tag import AdminTaggedItemsView
|
||||||
from seahub.api2.endpoints.admin.login_logs import LoginLogs, AdminLoginLogs
|
from seahub.api2.endpoints.admin.login_logs import LoginLogs, AdminLoginLogs
|
||||||
@@ -212,6 +212,7 @@ from seahub.api2.endpoints.subscription import SubscriptionView, SubscriptionPla
|
|||||||
from seahub.api2.endpoints.metadata_manage import MetadataRecords, MetadataManage, MetadataColumns, MetadataRecordInfo, \
|
from seahub.api2.endpoints.metadata_manage import MetadataRecords, MetadataManage, MetadataColumns, MetadataRecordInfo, \
|
||||||
MetadataViews, MetadataViewsMoveView, MetadataViewsDetailView, MetadataViewsDuplicateView
|
MetadataViews, MetadataViewsMoveView, MetadataViewsDetailView, MetadataViewsDuplicateView
|
||||||
from seahub.api2.endpoints.user_list import UserListView
|
from seahub.api2.endpoints.user_list import UserListView
|
||||||
|
from seahub.api2.endpoints.seahub_io import SeahubIOStatus
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -911,7 +912,7 @@ if is_pro_version():
|
|||||||
re_path(r'^api/v2.1/admin/logs/perm-audit/$', PermAudit.as_view(), name='api-v2.1-admin-logs-perm-audit'),
|
re_path(r'^api/v2.1/admin/logs/perm-audit/$', PermAudit.as_view(), name='api-v2.1-admin-logs-perm-audit'),
|
||||||
|
|
||||||
re_path(r'^api/v2.1/admin/logs/export-excel/$', SysLogsExport.as_view(), name='api-v2.1-admin-logs-export-excel'),
|
re_path(r'^api/v2.1/admin/logs/export-excel/$', SysLogsExport.as_view(), name='api-v2.1-admin-logs-export-excel'),
|
||||||
re_path(r'^api/v2.1/query-export-status/$', FileLogsExportStatus.as_view(), name='api-v2.1-query-export-status'),
|
re_path(r'^api/v2.1/query-io-status/$', SeahubIOStatus.as_view(), name='api-v2.1-query-export-status'),
|
||||||
path('sys/log/export-excel/', sys_log_export_excel, name='sys_log_export_excel'),
|
path('sys/log/export-excel/', sys_log_export_excel, name='sys_log_export_excel'),
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user