mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-13 05:39:59 +00:00
optimize log user selector
This commit is contained in:
@@ -1,7 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.activity-details {
|
.activity-details {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -16,6 +12,7 @@
|
|||||||
|
|
||||||
.cur-activity-modifiers {
|
.cur-activity-modifiers {
|
||||||
margin-left: -0.5rem;
|
margin-left: -0.5rem;
|
||||||
|
padding: 0.15rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cur-activity-modifiers:hover {
|
.cur-activity-modifiers:hover {
|
||||||
|
155
frontend/src/pages/dashboard/log-repo-selector.js
Normal file
155
frontend/src/pages/dashboard/log-repo-selector.js
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Input } from 'reactstrap';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
import '../../css/log-filter.css';
|
||||||
|
|
||||||
|
class LogRepoSelector extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isOpen: false,
|
||||||
|
query: '',
|
||||||
|
isLoading: false,
|
||||||
|
searchResults: []
|
||||||
|
};
|
||||||
|
this.dropdownRef = React.createRef();
|
||||||
|
this.finalValue = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.addEventListener('click', this.handleClickOutside);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
document.removeEventListener('click', this.handleClickOutside);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClickOutside = (e) => {
|
||||||
|
const { isOpen } = this.state;
|
||||||
|
if (isOpen && !this.repoSelector.contains(e.target)) {
|
||||||
|
this.togglePopover();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
togglePopover = () => {
|
||||||
|
const { isOpen } = this.state;
|
||||||
|
if (isOpen) {
|
||||||
|
this.props.onSelect(null, true);
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
isOpen: !isOpen
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onToggleClick = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
this.togglePopover();
|
||||||
|
};
|
||||||
|
|
||||||
|
onQueryChange = (e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
this.setState({ query: value });
|
||||||
|
this.searchRepos(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
searchRepos = (value) => {
|
||||||
|
this.finalValue = value;
|
||||||
|
if (value.length > 0) {
|
||||||
|
this.setState({ isLoading: true });
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.finalValue === value) {
|
||||||
|
const filteredItems = this.props.items.filter(item =>
|
||||||
|
item.name.toLowerCase().includes(value.trim().toLowerCase())
|
||||||
|
);
|
||||||
|
this.setState({
|
||||||
|
searchResults: filteredItems,
|
||||||
|
isLoading: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
} else {
|
||||||
|
this.setState({ searchResults: [] });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleSelectItem = (e, item) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
this.props.onSelect(item, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { isOpen, query, isLoading, searchResults } = this.state;
|
||||||
|
const { selectedItems } = this.props;
|
||||||
|
const displayItems = query.trim() ? searchResults : this.props.items;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-4 position-relative" ref={this.dropdownRef}>
|
||||||
|
<span className="cur-activity-modifiers d-inline-block p-2 rounded" onClick={this.onToggleClick}>
|
||||||
|
{selectedItems.length > 0 ? (
|
||||||
|
<>
|
||||||
|
<span>{gettext('Libraries:')}</span>
|
||||||
|
<span className="d-inline-block ml-1">{selectedItems.map(item => item.name).join(', ')}</span>
|
||||||
|
</>
|
||||||
|
) : gettext('Libraries')}
|
||||||
|
<i className="sf3-font sf3-font-down ml-2 toggle-icon"></i>
|
||||||
|
</span>
|
||||||
|
{isOpen && (
|
||||||
|
<div className="position-absolute activity-modifier-selector-container rounded shadow" ref={ref => this.repoSelector = ref}>
|
||||||
|
<ul className="activity-selected-modifiers px-3 py-1 list-unstyled">
|
||||||
|
{selectedItems.map((item, index) => (
|
||||||
|
<li key={index} className="activity-selected-modifier">
|
||||||
|
<i className="fas fa-folder"></i>
|
||||||
|
<span className="activity-user-name ml-2">{item.name}</span>
|
||||||
|
<i className="sf2-icon-close unselect-activity-user ml-2" onClick={(e) => {this.toggleSelectItem(e, item);}}></i>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<div className="px-3 pt-3">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
placeholder={gettext('Find libraries')}
|
||||||
|
value={query}
|
||||||
|
onChange={this.onQueryChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ul className="activity-user-list list-unstyled p-3 o-auto">
|
||||||
|
{isLoading ? (
|
||||||
|
<li className="text-center">{gettext('Loading...')}</li>
|
||||||
|
) : displayItems.length === 0 ? (
|
||||||
|
<li className="text-center">
|
||||||
|
{query ? gettext('Library not found') : gettext('Enter characters to start searching')}
|
||||||
|
</li>
|
||||||
|
) : (
|
||||||
|
displayItems.map((item, index) => {
|
||||||
|
const isSelected = selectedItems.some(selected => selected.repo_id === item.repo_id);
|
||||||
|
return (
|
||||||
|
<li key={index}
|
||||||
|
className="activity-user-item h-6 p-1 rounded d-flex justify-content-between align-items-center"
|
||||||
|
onClick={(e) => {this.toggleSelectItem(e, item);}}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<i className="fas fa-folder"></i>
|
||||||
|
<span className="activity-user-name ml-2">{item.name}</span>
|
||||||
|
</div>
|
||||||
|
{isSelected && <i className="sf2-icon-tick text-gray font-weight-bold"></i>}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogRepoSelector.propTypes = {
|
||||||
|
items: PropTypes.array.isRequired,
|
||||||
|
selectedItems: PropTypes.array.isRequired,
|
||||||
|
onSelect: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LogRepoSelector;
|
@@ -3,17 +3,22 @@ import PropTypes from 'prop-types';
|
|||||||
import { Input } from 'reactstrap';
|
import { Input } from 'reactstrap';
|
||||||
import { gettext } from '../../utils/constants';
|
import { gettext } from '../../utils/constants';
|
||||||
import '../../css/log-filter.css';
|
import '../../css/log-filter.css';
|
||||||
|
import { systemAdminAPI } from '../../utils/system-admin-api'
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
import toaster from '../../components/toast';
|
||||||
|
|
||||||
class LogFilter extends Component {
|
class LogUserSelector extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
searchText: '',
|
query: '',
|
||||||
query: ''
|
searchResults: [],
|
||||||
|
isLoading: false
|
||||||
};
|
};
|
||||||
this.dropdownRef = React.createRef();
|
this.dropdownRef = React.createRef();
|
||||||
|
this.finalValue = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -46,12 +51,33 @@ class LogFilter extends Component {
|
|||||||
this.togglePopover();
|
this.togglePopover();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleSearch = (e) => {
|
onQueryChange = (e) => {
|
||||||
this.setState({ searchText: e.target.value });
|
const value = e.target.value;
|
||||||
|
this.setState({ query: value });
|
||||||
|
this.searchUsers(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
onQueryChange = (e) => {
|
searchUsers = (value) => {
|
||||||
this.setState({ query: e.target.value });
|
this.finalValue = value;
|
||||||
|
if (value.length > 0) {
|
||||||
|
this.setState({ isLoading: true });
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.finalValue === value) {
|
||||||
|
systemAdminAPI.sysAdminSearchUsers(value).then((res) => {
|
||||||
|
this.setState({
|
||||||
|
searchResults: res.data.user_list,
|
||||||
|
isLoading: false
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
this.setState({ isLoading: false });
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
} else {
|
||||||
|
this.setState({ searchResults: [] });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleSelectItem = (e, item) => {
|
toggleSelectItem = (e, item) => {
|
||||||
@@ -60,16 +86,12 @@ class LogFilter extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isOpen, query } = this.state;
|
const { isOpen, query, searchResults, isLoading } = this.state;
|
||||||
const { items, selectedItems } = this.props;
|
const { selectedItems } = this.props;
|
||||||
const filteredItems = query.trim() ?
|
const displayItems = query.trim() ? searchResults : this.props.items;
|
||||||
items.filter(item =>
|
|
||||||
item.email.toLowerCase().includes(query.trim().toLowerCase()) ||
|
|
||||||
item.name.toLowerCase().includes(query.trim().toLowerCase())
|
|
||||||
) : items;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-4 position-relative" ref={this.dropdownRef}>
|
<div className="position-relative" ref={this.dropdownRef}>
|
||||||
<span className="cur-activity-modifiers d-inline-block p-2 rounded" onClick={this.onToggleClick}>
|
<span className="cur-activity-modifiers d-inline-block p-2 rounded" onClick={this.onToggleClick}>
|
||||||
{selectedItems.length > 0 ? (
|
{selectedItems.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
@@ -101,17 +123,29 @@ class LogFilter extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ul className="activity-user-list list-unstyled p-3 o-auto">
|
<ul className="activity-user-list list-unstyled p-3 o-auto">
|
||||||
{filteredItems.map((item, index) => {
|
{isLoading ? (
|
||||||
|
<li className="text-center">{gettext('Loading...')}</li>
|
||||||
|
) : displayItems.length === 0 ? (
|
||||||
|
<li className="text-center">
|
||||||
|
{query ? gettext('User not found') : gettext('Enter characters to start searching')}
|
||||||
|
</li>
|
||||||
|
) : (
|
||||||
|
displayItems.map((item, index) => {
|
||||||
|
const isSelected = selectedItems.some(selected => selected.email === item.email);
|
||||||
return (
|
return (
|
||||||
<li key={index} className="activity-user-item h-6 p-1 rounded d-flex justify-content-between align-items-center" onClick={(e) => {this.toggleSelectItem(e, item);}}>
|
<li key={index}
|
||||||
|
className="activity-user-item h-6 p-1 rounded d-flex justify-content-between align-items-center"
|
||||||
|
onClick={(e) => {this.toggleSelectItem(e, item);}}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<img src={item.avatar_url} className="avatar w-5 h-5" alt="" />
|
<img src={item.avatar_url} className="avatar w-5 h-5" alt="" />
|
||||||
<span className="activity-user-name ml-2">{item.name}</span>
|
<span className="activity-user-name ml-2">{item.name}</span>
|
||||||
</div>
|
</div>
|
||||||
{item.isSelected && <i className="sf2-icon-tick text-gray font-weight-bold"></i>}
|
{isSelected && <i className="sf2-icon-tick text-gray font-weight-bold"></i>}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})}
|
})
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -120,10 +154,10 @@ class LogFilter extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogFilter.propTypes = {
|
LogUserSelector.propTypes = {
|
||||||
items: PropTypes.array.isRequired,
|
items: PropTypes.array.isRequired,
|
||||||
selectedItems: PropTypes.array.isRequired,
|
selectedItems: PropTypes.array.isRequired,
|
||||||
onSelect: PropTypes.func.isRequired
|
onSelect: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LogFilter;
|
export default LogUserSelector;
|
@@ -17,6 +17,8 @@ import FilterMenu from './file-access-item-menu';
|
|||||||
import ToggleFilter from './file-access-toggle-filter';
|
import ToggleFilter from './file-access-toggle-filter';
|
||||||
import MainPanelTopbar from '../main-panel-topbar';
|
import MainPanelTopbar from '../main-panel-topbar';
|
||||||
import UserLink from '../user-link';
|
import UserLink from '../user-link';
|
||||||
|
import LogUserSelector from '../../dashboard/log-user-selector'
|
||||||
|
import LogRepoSelector from '../../dashboard/log-repo-selector';
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
@@ -248,6 +250,8 @@ class FileAccessLogs extends Component {
|
|||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
isExportExcelDialogOpen: false,
|
isExportExcelDialogOpen: false,
|
||||||
|
availableUsers: [],
|
||||||
|
selectedUsers: [],
|
||||||
};
|
};
|
||||||
this.initPage = 1;
|
this.initPage = 1;
|
||||||
}
|
}
|
||||||
@@ -265,13 +269,15 @@ class FileAccessLogs extends Component {
|
|||||||
userFilteredBy: urlParams.get('email'),
|
userFilteredBy: urlParams.get('email'),
|
||||||
repoFilteredBy: urlParams.get('repo_id')
|
repoFilteredBy: urlParams.get('repo_id')
|
||||||
}, () => {
|
}, () => {
|
||||||
|
// this.getAvailableUsers();
|
||||||
this.getLogsByPage(this.state.currentPage);
|
this.getLogsByPage(this.state.currentPage);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getLogsByPage = (page) => {
|
getLogsByPage = (page) => {
|
||||||
const { perPage, userFilteredBy, repoFilteredBy } = this.state;
|
const { perPage, userFilteredBy, repoFilteredBy, selectedUsers } = this.state;
|
||||||
systemAdminAPI.sysAdminListFileAccessLogs(page, perPage, userFilteredBy, repoFilteredBy).then((res) => {
|
let emails = selectedUsers.map(user => user.email);
|
||||||
|
systemAdminAPI.sysAdminListFileAccessLogs(page, perPage, emails, repoFilteredBy).then((res) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
logList: res.data.file_access_log_list,
|
logList: res.data.file_access_log_list,
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -322,12 +328,51 @@ class FileAccessLogs extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getAvailableUsers = () => {
|
||||||
|
systemAdminAPI.sysAdminListUsers().then((res) => {
|
||||||
|
this.setState({
|
||||||
|
availableUsers: res.data.data
|
||||||
|
});
|
||||||
|
}).catch((error) => {
|
||||||
|
this.setState({
|
||||||
|
errorMsg: Utils.getErrorMsg(error, true)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleUserFilter = (user, shouldFetchData = true) => {
|
||||||
|
const { selectedUsers } = this.state;
|
||||||
|
let newSelectedUsers;
|
||||||
|
|
||||||
|
if (user === null) {
|
||||||
|
newSelectedUsers = selectedUsers;
|
||||||
|
} else {
|
||||||
|
const isSelected = selectedUsers.find(item => item.email === user.email);
|
||||||
|
if (isSelected) {
|
||||||
|
newSelectedUsers = selectedUsers.filter(item => item.email !== user.email);
|
||||||
|
} else {
|
||||||
|
newSelectedUsers = [...selectedUsers, user];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
selectedUsers: newSelectedUsers,
|
||||||
|
currentPage: 1
|
||||||
|
}, () => {
|
||||||
|
if (shouldFetchData) {
|
||||||
|
this.getLogsByPage(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
logList,
|
logList,
|
||||||
userFilteredBy, repoFilteredBy,
|
userFilteredBy, repoFilteredBy,
|
||||||
currentPage, perPage, hasNextPage,
|
currentPage, perPage, hasNextPage,
|
||||||
isExportExcelDialogOpen
|
isExportExcelDialogOpen,
|
||||||
|
availableUsers,
|
||||||
|
selectedUsers
|
||||||
} = this.state;
|
} = this.state;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
@@ -338,6 +383,12 @@ class FileAccessLogs extends Component {
|
|||||||
<div className="cur-view-container">
|
<div className="cur-view-container">
|
||||||
<LogsNav currentItem="fileAccessLogs" />
|
<LogsNav currentItem="fileAccessLogs" />
|
||||||
<div className="cur-view-content">
|
<div className="cur-view-content">
|
||||||
|
<Fragment>
|
||||||
|
<LogUserSelector
|
||||||
|
items={availableUsers}
|
||||||
|
selectedItems={selectedUsers}
|
||||||
|
onSelect={this.handleUserFilter}
|
||||||
|
/>
|
||||||
<Content
|
<Content
|
||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
errorMsg={this.state.errorMsg}
|
errorMsg={this.state.errorMsg}
|
||||||
@@ -352,6 +403,7 @@ class FileAccessLogs extends Component {
|
|||||||
getLogsByPage={this.getLogsByPage}
|
getLogsByPage={this.getLogsByPage}
|
||||||
resetPerPage={this.resetPerPage}
|
resetPerPage={this.resetPerPage}
|
||||||
/>
|
/>
|
||||||
|
</Fragment>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { Link } from '@gatsbyjs/reach-router';
|
import { Link } from '@gatsbyjs/reach-router';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
import { seafileAPI } from '../../../utils/seafile-api';
|
import { systemAdminAPI } from '../../../utils/system-admin-api';
|
||||||
import { gettext, siteRoot } from '../../../utils/constants';
|
import { gettext, siteRoot } from '../../../utils/constants';
|
||||||
import { Utils } from '../../../utils/utils';
|
import { Utils } from '../../../utils/utils';
|
||||||
import EmptyTip from '../../../components/empty-tip';
|
import EmptyTip from '../../../components/empty-tip';
|
||||||
@@ -12,6 +12,7 @@ import Paginator from '../../../components/paginator';
|
|||||||
import MainPanelTopbar from '../main-panel-topbar';
|
import MainPanelTopbar from '../main-panel-topbar';
|
||||||
import UserLink from '../user-link';
|
import UserLink from '../user-link';
|
||||||
import LogsNav from './logs-nav';
|
import LogsNav from './logs-nav';
|
||||||
|
import LogUserSelector from '../../dashboard/log-user-selector';
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
@@ -162,6 +163,8 @@ class FIleTransferLogs extends Component {
|
|||||||
perPage: 100,
|
perPage: 100,
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
|
availableUsers: [],
|
||||||
|
selectedUsers: [],
|
||||||
};
|
};
|
||||||
this.initPage = 1;
|
this.initPage = 1;
|
||||||
}
|
}
|
||||||
@@ -178,8 +181,9 @@ class FIleTransferLogs extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getLogsByPage = (page) => {
|
getLogsByPage = (page) => {
|
||||||
let { perPage } = this.state;
|
let { perPage, selectedUsers } = this.state;
|
||||||
seafileAPI.sysAdminListFileTransferLogs(page, perPage).then((res) => {
|
let emails = selectedUsers.map(user => user.email);
|
||||||
|
systemAdminAPI.sysAdminListFileTransferLogs(page, perPage, emails).then((res) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
logList: res.data.repo_transfer_log_list,
|
logList: res.data.repo_transfer_log_list,
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -200,8 +204,33 @@ class FIleTransferLogs extends Component {
|
|||||||
}, () => this.getLogsByPage(this.initPage));
|
}, () => this.getLogsByPage(this.initPage));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleUserFilter = (user, shouldFetchData = true) => {
|
||||||
|
const { selectedUsers } = this.state;
|
||||||
|
let newSelectedUsers;
|
||||||
|
|
||||||
|
if (user === null) {
|
||||||
|
newSelectedUsers = selectedUsers;
|
||||||
|
} else {
|
||||||
|
const isSelected = selectedUsers.find(item => item.email === user.email);
|
||||||
|
if (isSelected) {
|
||||||
|
newSelectedUsers = selectedUsers.filter(item => item.email !== user.email);
|
||||||
|
} else {
|
||||||
|
newSelectedUsers = [...selectedUsers, user];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
selectedUsers: newSelectedUsers,
|
||||||
|
currentPage: 1
|
||||||
|
}, () => {
|
||||||
|
if (shouldFetchData) {
|
||||||
|
this.getLogsByPage(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { logList, currentPage, perPage, hasNextPage } = this.state;
|
let { logList, currentPage, perPage, hasNextPage, availableUsers, selectedUsers } = this.state;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<MainPanelTopbar {...this.props} />
|
<MainPanelTopbar {...this.props} />
|
||||||
@@ -209,6 +238,13 @@ class FIleTransferLogs extends Component {
|
|||||||
<div className="cur-view-container">
|
<div className="cur-view-container">
|
||||||
<LogsNav currentItem="fileTransfer" />
|
<LogsNav currentItem="fileTransfer" />
|
||||||
<div className="cur-view-content">
|
<div className="cur-view-content">
|
||||||
|
<Fragment>
|
||||||
|
<LogUserSelector
|
||||||
|
label={gettext('User')}
|
||||||
|
items={availableUsers}
|
||||||
|
selectedItems={selectedUsers}
|
||||||
|
onSelect={this.handleUserFilter}
|
||||||
|
/>
|
||||||
<Content
|
<Content
|
||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
errorMsg={this.state.errorMsg}
|
errorMsg={this.state.errorMsg}
|
||||||
@@ -219,6 +255,7 @@ class FIleTransferLogs extends Component {
|
|||||||
getLogsByPage={this.getLogsByPage}
|
getLogsByPage={this.getLogsByPage}
|
||||||
resetPerPage={this.resetPerPage}
|
resetPerPage={this.resetPerPage}
|
||||||
/>
|
/>
|
||||||
|
</Fragment>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -15,6 +15,7 @@ import UserLink from '../user-link';
|
|||||||
import ModalPortal from '../../../components/modal-portal';
|
import ModalPortal from '../../../components/modal-portal';
|
||||||
import CommitDetails from '../../../components/dialog/commit-details';
|
import CommitDetails from '../../../components/dialog/commit-details';
|
||||||
import LogsExportExcelDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-logs-export-excel-dialog';
|
import LogsExportExcelDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-logs-export-excel-dialog';
|
||||||
|
import LogUserSelector from '../../dashboard/log-user-selector'
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
@@ -173,6 +174,8 @@ class FileUpdateLogs extends Component {
|
|||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
isExportExcelDialogOpen: false,
|
isExportExcelDialogOpen: false,
|
||||||
|
availableUsers: [],
|
||||||
|
selectedUsers: [],
|
||||||
};
|
};
|
||||||
this.initPage = 1;
|
this.initPage = 1;
|
||||||
}
|
}
|
||||||
@@ -193,8 +196,10 @@ class FileUpdateLogs extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getLogsByPage = (page) => {
|
getLogsByPage = (page) => {
|
||||||
let { perPage } = this.state;
|
let { perPage, selectedUsers } = this.state;
|
||||||
systemAdminAPI.sysAdminListFileUpdateLogs(page, perPage).then((res) => {
|
let emails = selectedUsers.map(user => user.email);
|
||||||
|
|
||||||
|
systemAdminAPI.sysAdminListFileUpdateLogs(page, perPage, emails).then((res) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
logList: res.data.file_update_log_list,
|
logList: res.data.file_update_log_list,
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -215,8 +220,34 @@ class FileUpdateLogs extends Component {
|
|||||||
}, () => this.getLogsByPage(this.initPage));
|
}, () => this.getLogsByPage(this.initPage));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
handleUserFilter = (user, shouldFetchData = true) => {
|
||||||
|
const { selectedUsers } = this.state;
|
||||||
|
let newSelectedUsers;
|
||||||
|
|
||||||
|
if (user === null) {
|
||||||
|
newSelectedUsers = selectedUsers;
|
||||||
|
} else {
|
||||||
|
const isSelected = selectedUsers.find(item => item.email === user.email);
|
||||||
|
if (isSelected) {
|
||||||
|
newSelectedUsers = selectedUsers.filter(item => item.email !== user.email);
|
||||||
|
} else {
|
||||||
|
newSelectedUsers = [...selectedUsers, user];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
selectedUsers: newSelectedUsers,
|
||||||
|
currentPage: 1
|
||||||
|
}, () => {
|
||||||
|
if (shouldFetchData) {
|
||||||
|
this.getLogsByPage(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { logList, currentPage, perPage, hasNextPage, isExportExcelDialogOpen } = this.state;
|
let { logList, currentPage, perPage, hasNextPage, isExportExcelDialogOpen, availableUsers, selectedUsers } = this.state;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<MainPanelTopbar {...this.props}>
|
<MainPanelTopbar {...this.props}>
|
||||||
@@ -226,6 +257,13 @@ class FileUpdateLogs extends Component {
|
|||||||
<div className="cur-view-container">
|
<div className="cur-view-container">
|
||||||
<LogsNav currentItem="fileUpdateLogs" />
|
<LogsNav currentItem="fileUpdateLogs" />
|
||||||
<div className="cur-view-content">
|
<div className="cur-view-content">
|
||||||
|
<Fragment>
|
||||||
|
<LogUserSelector
|
||||||
|
label={gettext('User')}
|
||||||
|
items={availableUsers}
|
||||||
|
selectedItems={selectedUsers}
|
||||||
|
onSelect={this.handleUserFilter}
|
||||||
|
/>
|
||||||
<Content
|
<Content
|
||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
errorMsg={this.state.errorMsg}
|
errorMsg={this.state.errorMsg}
|
||||||
@@ -236,6 +274,7 @@ class FileUpdateLogs extends Component {
|
|||||||
getLogsByPage={this.getLogsByPage}
|
getLogsByPage={this.getLogsByPage}
|
||||||
resetPerPage={this.resetPerPage}
|
resetPerPage={this.resetPerPage}
|
||||||
/>
|
/>
|
||||||
|
</Fragment>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -14,7 +14,7 @@ import MainPanelTopbar from '../main-panel-topbar';
|
|||||||
import UserLink from '../user-link';
|
import UserLink from '../user-link';
|
||||||
import LogsExportExcelDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-logs-export-excel-dialog';
|
import LogsExportExcelDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-logs-export-excel-dialog';
|
||||||
import ModalPortal from '../../../components/modal-portal';
|
import ModalPortal from '../../../components/modal-portal';
|
||||||
import LogFilter from '../../dashboard/log-filter';
|
import LogUserSelector from '../../dashboard/log-user-selector';
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ class LoginLogs extends Component {
|
|||||||
perPage: parseInt(urlParams.get('per_page') || perPage),
|
perPage: parseInt(urlParams.get('per_page') || perPage),
|
||||||
currentPage: parseInt(urlParams.get('page') || currentPage)
|
currentPage: parseInt(urlParams.get('page') || currentPage)
|
||||||
}, () => {
|
}, () => {
|
||||||
this.getAvailableUsers();
|
// this.getAvailableUsers();
|
||||||
this.getLogsByPage(this.state.currentPage);
|
this.getLogsByPage(this.state.currentPage);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -235,7 +235,7 @@ class LoginLogs extends Component {
|
|||||||
<LogsNav currentItem="loginLogs" />
|
<LogsNav currentItem="loginLogs" />
|
||||||
<div className="cur-view-content">
|
<div className="cur-view-content">
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<LogFilter
|
<LogUserSelector
|
||||||
label={gettext('User')}
|
label={gettext('User')}
|
||||||
items={availableUsers}
|
items={availableUsers}
|
||||||
selectedItems={selectedUsers}
|
selectedItems={selectedUsers}
|
||||||
|
@@ -15,6 +15,7 @@ import Paginator from '../../../components/paginator';
|
|||||||
import MainPanelTopbar from '../main-panel-topbar';
|
import MainPanelTopbar from '../main-panel-topbar';
|
||||||
import UserLink from '../user-link';
|
import UserLink from '../user-link';
|
||||||
import LogsNav from './logs-nav';
|
import LogsNav from './logs-nav';
|
||||||
|
import LogUserSelector from '../../dashboard/log-user-selector';
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
@@ -151,6 +152,8 @@ class SharePermissionLogs extends Component {
|
|||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
isExportExcelDialogOpen: false,
|
isExportExcelDialogOpen: false,
|
||||||
|
availableUsers: [],
|
||||||
|
selectedUsers: [],
|
||||||
};
|
};
|
||||||
this.initPage = 1;
|
this.initPage = 1;
|
||||||
}
|
}
|
||||||
@@ -171,8 +174,9 @@ class SharePermissionLogs extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getLogsByPage = (page) => {
|
getLogsByPage = (page) => {
|
||||||
let { perPage } = this.state;
|
let { perPage, selectedUsers } = this.state;
|
||||||
systemAdminAPI.sysAdminListSharePermissionLogs(page, perPage).then((res) => {
|
let emails = selectedUsers.map(user => user.email);
|
||||||
|
systemAdminAPI.sysAdminListSharePermissionLogs(page, perPage, emails).then((res) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
logList: res.data.share_permission_log_list,
|
logList: res.data.share_permission_log_list,
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -193,8 +197,33 @@ class SharePermissionLogs extends Component {
|
|||||||
}, () => this.getLogsByPage(this.initPage));
|
}, () => this.getLogsByPage(this.initPage));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleUserFilter = (user, shouldFetchData = true) => {
|
||||||
|
const { selectedUsers } = this.state;
|
||||||
|
let newSelectedUsers;
|
||||||
|
|
||||||
|
if (user === null) {
|
||||||
|
newSelectedUsers = selectedUsers;
|
||||||
|
} else {
|
||||||
|
const isSelected = selectedUsers.find(item => item.email === user.email);
|
||||||
|
if (isSelected) {
|
||||||
|
newSelectedUsers = selectedUsers.filter(item => item.email !== user.email);
|
||||||
|
} else {
|
||||||
|
newSelectedUsers = [...selectedUsers, user];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
selectedUsers: newSelectedUsers,
|
||||||
|
currentPage: 1
|
||||||
|
}, () => {
|
||||||
|
if (shouldFetchData) {
|
||||||
|
this.getLogsByPage(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { logList, currentPage, perPage, hasNextPage, isExportExcelDialogOpen } = this.state;
|
let { logList, currentPage, perPage, hasNextPage, isExportExcelDialogOpen, availableUsers, selectedUsers } = this.state;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<MainPanelTopbar {...this.props}>
|
<MainPanelTopbar {...this.props}>
|
||||||
@@ -204,6 +233,13 @@ class SharePermissionLogs extends Component {
|
|||||||
<div className="cur-view-container">
|
<div className="cur-view-container">
|
||||||
<LogsNav currentItem="sharePermissionLogs" />
|
<LogsNav currentItem="sharePermissionLogs" />
|
||||||
<div className="cur-view-content">
|
<div className="cur-view-content">
|
||||||
|
<Fragment>
|
||||||
|
<LogUserSelector
|
||||||
|
label={gettext('User')}
|
||||||
|
items={availableUsers}
|
||||||
|
selectedItems={selectedUsers}
|
||||||
|
onSelect={this.handleUserFilter}
|
||||||
|
/>
|
||||||
<Content
|
<Content
|
||||||
loading={this.state.loading}
|
loading={this.state.loading}
|
||||||
errorMsg={this.state.errorMsg}
|
errorMsg={this.state.errorMsg}
|
||||||
@@ -214,6 +250,7 @@ class SharePermissionLogs extends Component {
|
|||||||
getLogsByPage={this.getLogsByPage}
|
getLogsByPage={this.getLogsByPage}
|
||||||
resetPerPage={this.resetPerPage}
|
resetPerPage={this.resetPerPage}
|
||||||
/>
|
/>
|
||||||
|
</Fragment>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -692,14 +692,14 @@ class SystemAdminAPI {
|
|||||||
return this.req.get(url, { params: params });
|
return this.req.get(url, { params: params });
|
||||||
}
|
}
|
||||||
|
|
||||||
sysAdminListFileAccessLogs(page, perPage, email, repoID) {
|
sysAdminListFileAccessLogs(page, perPage, emails, repoID) {
|
||||||
const url = this.server + '/api/v2.1/admin/logs/file-access-logs/';
|
const url = this.server + '/api/v2.1/admin/logs/file-access-logs/';
|
||||||
let params = {
|
let params = {
|
||||||
page: page,
|
page: page,
|
||||||
per_page: perPage
|
per_page: perPage
|
||||||
};
|
};
|
||||||
if (email != undefined) {
|
if (emails && emails.length) {
|
||||||
params.email = email;
|
params.emails = emails.join(',');
|
||||||
}
|
}
|
||||||
if (repoID != undefined) {
|
if (repoID != undefined) {
|
||||||
params.repo_id = repoID;
|
params.repo_id = repoID;
|
||||||
@@ -707,21 +707,48 @@ class SystemAdminAPI {
|
|||||||
return this.req.get(url, { params: params });
|
return this.req.get(url, { params: params });
|
||||||
}
|
}
|
||||||
|
|
||||||
sysAdminListFileUpdateLogs(page, perPage) {
|
sysAdminListFileUpdateLogs(page, perPage, emails, repoID) {
|
||||||
const url = this.server + '/api/v2.1/admin/logs/file-update-logs/';
|
const url = this.server + '/api/v2.1/admin/logs/file-update-logs/';
|
||||||
let params = {
|
let params = {
|
||||||
page: page,
|
page: page,
|
||||||
per_page: perPage
|
per_page: perPage
|
||||||
};
|
};
|
||||||
|
if (emails && emails.length) {
|
||||||
|
params.emails = emails.join(',');
|
||||||
|
}
|
||||||
|
if (repoID != undefined) {
|
||||||
|
params.repo_id = repoID;
|
||||||
|
}
|
||||||
return this.req.get(url, { params: params });
|
return this.req.get(url, { params: params });
|
||||||
}
|
}
|
||||||
|
|
||||||
sysAdminListSharePermissionLogs(page, perPage) {
|
sysAdminListSharePermissionLogs(page, perPage, emails, repoID) {
|
||||||
const url = this.server + '/api/v2.1/admin/logs/share-permission-logs/';
|
const url = this.server + '/api/v2.1/admin/logs/share-permission-logs/';
|
||||||
let params = {
|
let params = {
|
||||||
page: page,
|
page: page,
|
||||||
per_page: perPage
|
per_page: perPage
|
||||||
};
|
};
|
||||||
|
if (emails && emails.length) {
|
||||||
|
params.emails = emails.join(',');
|
||||||
|
}
|
||||||
|
if (repoID != undefined) {
|
||||||
|
params.repo_id = repoID;
|
||||||
|
}
|
||||||
|
return this.req.get(url, { params: params });
|
||||||
|
}
|
||||||
|
|
||||||
|
sysAdminListFileTransferLogs(page, perPage, emails, repoID) {
|
||||||
|
const url = this.server + '/api/v2.1/admin/logs/repo-transfer-logs/';
|
||||||
|
let params = {
|
||||||
|
page: page,
|
||||||
|
per_page: perPage
|
||||||
|
};
|
||||||
|
if (emails && emails.length) {
|
||||||
|
params.emails = emails.join(',');
|
||||||
|
}
|
||||||
|
if (repoID != undefined) {
|
||||||
|
params.repo_id = repoID;
|
||||||
|
}
|
||||||
return this.req.get(url, { params: params });
|
return this.req.get(url, { params: params });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,7 +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 django.db.models import Q
|
||||||
from seaserv import ccnet_api, seafile_api
|
from seaserv import ccnet_api, seafile_api
|
||||||
|
|
||||||
from seahub.api2.authentication import TokenAuthentication
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
@@ -16,7 +16,7 @@ from seahub.api2.utils import api_error
|
|||||||
|
|
||||||
from seahub.base.templatetags.seahub_tags import email2nickname, \
|
from seahub.base.templatetags.seahub_tags import email2nickname, \
|
||||||
email2contact_email, translate_commit_desc
|
email2contact_email, translate_commit_desc
|
||||||
from seahub.utils import get_file_audit_events, generate_file_audit_event_type, \
|
from seahub.utils import get_log_events_by_type_users_repo, generate_file_audit_event_type, \
|
||||||
get_file_update_events, get_perm_audit_events, is_valid_email
|
get_file_update_events, get_perm_audit_events, is_valid_email
|
||||||
from seahub.utils.timeutils import datetime_to_isoformat_timestr, utc_datetime_to_isoformat_timestr
|
from seahub.utils.timeutils import datetime_to_isoformat_timestr, utc_datetime_to_isoformat_timestr
|
||||||
from seahub.utils.repo import is_valid_repo_id_format
|
from seahub.utils.repo import is_valid_repo_id_format
|
||||||
@@ -114,8 +114,10 @@ class AdminLogsFileAccessLogs(APIView):
|
|||||||
current_page = 1
|
current_page = 1
|
||||||
per_page = 100
|
per_page = 100
|
||||||
|
|
||||||
user_selected = request.GET.get('email', None)
|
emails = request.GET.get('emails')
|
||||||
if user_selected and not is_valid_email(user_selected):
|
emails = emails.split(',') if emails else []
|
||||||
|
for user_selected in emails:
|
||||||
|
if not is_valid_email(user_selected):
|
||||||
error_msg = 'email %s invalid.' % user_selected
|
error_msg = 'email %s invalid.' % user_selected
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
@@ -127,18 +129,7 @@ class AdminLogsFileAccessLogs(APIView):
|
|||||||
start = per_page * (current_page - 1)
|
start = per_page * (current_page - 1)
|
||||||
limit = per_page + 1
|
limit = per_page + 1
|
||||||
|
|
||||||
if user_selected:
|
events = get_log_events_by_type_users_repo('file_audit', emails, repo_id_selected, start, limit) or []
|
||||||
org_id = -1
|
|
||||||
orgs = ccnet_api.get_orgs_by_user(user_selected)
|
|
||||||
if orgs:
|
|
||||||
org_id = orgs[0].org_id
|
|
||||||
elif repo_id_selected:
|
|
||||||
org_id = seafile_api.get_org_id_by_repo_id(repo_id_selected)
|
|
||||||
else:
|
|
||||||
org_id = 0
|
|
||||||
|
|
||||||
# org_id = 0, show all file audit
|
|
||||||
events = get_file_audit_events(user_selected, org_id, repo_id_selected, start, limit) or []
|
|
||||||
|
|
||||||
if len(events) > per_page:
|
if len(events) > per_page:
|
||||||
events = events[:per_page]
|
events = events[:per_page]
|
||||||
@@ -220,8 +211,10 @@ class AdminLogsFileUpdateLogs(APIView):
|
|||||||
current_page = 1
|
current_page = 1
|
||||||
per_page = 100
|
per_page = 100
|
||||||
|
|
||||||
user_selected = request.GET.get('email', None)
|
emails = request.GET.get('emails')
|
||||||
if user_selected and not is_valid_email(user_selected):
|
emails = emails.split(',') if emails else []
|
||||||
|
for user_selected in emails:
|
||||||
|
if not is_valid_email(user_selected):
|
||||||
error_msg = 'email %s invalid.' % user_selected
|
error_msg = 'email %s invalid.' % user_selected
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
@@ -233,8 +226,7 @@ class AdminLogsFileUpdateLogs(APIView):
|
|||||||
start = per_page * (current_page - 1)
|
start = per_page * (current_page - 1)
|
||||||
limit = per_page
|
limit = per_page
|
||||||
|
|
||||||
# org_id = 0, show all file audit
|
events = get_log_events_by_type_users_repo('file_update', emails, repo_id_selected, start, limit)
|
||||||
events = get_file_update_events(user_selected, 0, repo_id_selected, start, limit) or []
|
|
||||||
|
|
||||||
has_next_page = True if len(events) == per_page else False
|
has_next_page = True if len(events) == per_page else False
|
||||||
|
|
||||||
@@ -306,8 +298,10 @@ class AdminLogsSharePermissionLogs(APIView):
|
|||||||
current_page = 1
|
current_page = 1
|
||||||
per_page = 100
|
per_page = 100
|
||||||
|
|
||||||
user_selected = request.GET.get('email', None)
|
emails = request.GET.get('emails')
|
||||||
if user_selected and not is_valid_email(user_selected):
|
emails = emails.split(',') if emails else []
|
||||||
|
for user_selected in emails:
|
||||||
|
if not is_valid_email(user_selected):
|
||||||
error_msg = 'email %s invalid.' % user_selected
|
error_msg = 'email %s invalid.' % user_selected
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
@@ -319,9 +313,7 @@ class AdminLogsSharePermissionLogs(APIView):
|
|||||||
start = per_page * (current_page - 1)
|
start = per_page * (current_page - 1)
|
||||||
limit = per_page
|
limit = per_page
|
||||||
|
|
||||||
# org_id = 0, show all file audit
|
events = get_log_events_by_type_users_repo('perm_audit', emails, repo_id_selected, start, limit) or []
|
||||||
events = get_perm_audit_events(user_selected, 0, repo_id_selected, start, limit) or []
|
|
||||||
|
|
||||||
has_next_page = True if len(events) == per_page else False
|
has_next_page = True if len(events) == per_page else False
|
||||||
|
|
||||||
# Use dict to reduce memcache fetch cost in large for-loop.
|
# Use dict to reduce memcache fetch cost in large for-loop.
|
||||||
@@ -461,6 +453,19 @@ class AdminLogsFileTransferLogs(APIView):
|
|||||||
error_msg = 'limit invalid'
|
error_msg = 'limit invalid'
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
emails = request.GET.get('emails')
|
||||||
|
emails = emails.split(',') if emails else []
|
||||||
|
for user_selected in emails:
|
||||||
|
if not is_valid_email(user_selected):
|
||||||
|
error_msg = 'email %s invalid.' % user_selected
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
if emails:
|
||||||
|
events = RepoTransfer.objects.filter(
|
||||||
|
Q(from_user__in=emails) |
|
||||||
|
Q(to__in=emails) |
|
||||||
|
Q(operator__in=emails)
|
||||||
|
).order_by('-timestamp')[start:start+limit+1]
|
||||||
|
else:
|
||||||
events = RepoTransfer.objects.all().order_by('-timestamp')[start:start+limit+1]
|
events = RepoTransfer.objects.all().order_by('-timestamp')[start:start+limit+1]
|
||||||
if len(events) > limit:
|
if len(events) > limit:
|
||||||
has_next_page = True
|
has_next_page = True
|
||||||
|
@@ -1162,6 +1162,8 @@ class AdminSearchUser(APIView):
|
|||||||
has_appended.append(user.email)
|
has_appended.append(user.email)
|
||||||
|
|
||||||
info = {}
|
info = {}
|
||||||
|
url, is_default, date_uploaded = api_avatar_url(user.email)
|
||||||
|
info['avatar_url'] = url
|
||||||
info['email'] = user.email
|
info['email'] = user.email
|
||||||
info['name'] = email2nickname(user.email)
|
info['name'] = email2nickname(user.email)
|
||||||
info['contact_email'] = email2contact_email(user.email)
|
info['contact_email'] = email2contact_email(user.email)
|
||||||
|
@@ -733,6 +733,12 @@ if EVENTS_CONFIG_FILE:
|
|||||||
|
|
||||||
return events if events else None
|
return events if events else None
|
||||||
|
|
||||||
|
def get_log_events_by_type_users_repo(type, emails, repo_ids, start, limit):
|
||||||
|
with _get_seafevents_session() as session:
|
||||||
|
events = seafevents_api.get_log_events_by_type_users_repo(session, type, emails, repo_ids, start, limit)
|
||||||
|
|
||||||
|
return events if events else None
|
||||||
|
|
||||||
def get_file_ops_stats_by_day(start, end, offset):
|
def get_file_ops_stats_by_day(start, end, offset):
|
||||||
""" return file audit record of sepcifiy time group by day.
|
""" return file audit record of sepcifiy time group by day.
|
||||||
"""
|
"""
|
||||||
@@ -886,6 +892,8 @@ else:
|
|||||||
pass
|
pass
|
||||||
def get_file_audit_events():
|
def get_file_audit_events():
|
||||||
pass
|
pass
|
||||||
|
def get_log_events_by_type_users_repo():
|
||||||
|
pass
|
||||||
def get_file_ops_stats_by_day():
|
def get_file_ops_stats_by_day():
|
||||||
pass
|
pass
|
||||||
def get_org_file_ops_stats_by_day():
|
def get_org_file_ops_stats_by_day():
|
||||||
|
Reference in New Issue
Block a user