bugfix, permission api rewrite
This commit is contained in:
@@ -54,6 +54,40 @@ export default function AccessControlList(props) {
|
||||
});
|
||||
}, [currentLocale]);
|
||||
|
||||
const onChangePermission = useCallback((methodIndex, groupId, selected) => {
|
||||
let newGroups = null;
|
||||
let currentGroups = acl[methodIndex].groups;
|
||||
let groupIndex = currentGroups.indexOf(groupId);
|
||||
if (!selected) {
|
||||
if (currentGroups.length === 0) {
|
||||
// it was an "everyone permission" before
|
||||
newGroups = groups.filter(group => group.id !== groupId).map(group => group.id);
|
||||
} else if (groupIndex !== -1 && currentGroups.length > 1) {
|
||||
newGroups = [...currentGroups];
|
||||
newGroups.splice(groupIndex, 1);
|
||||
}
|
||||
} else if (groupIndex === -1) {
|
||||
newGroups = [...currentGroups];
|
||||
newGroups.push(groupId);
|
||||
}
|
||||
|
||||
if (newGroups !== null) {
|
||||
props.api.updatePermission(acl[methodIndex].method, newGroups).then((data) => {
|
||||
if (data.success) {
|
||||
let newACL = [...acl];
|
||||
newACL[methodIndex].groups = newGroups;
|
||||
setACL(newACL);
|
||||
} else {
|
||||
props.showDialog("Error updating permission: " + data.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [acl]);
|
||||
|
||||
const isRestricted = (method) => {
|
||||
return ["permissions/update", "permissions/delete"].includes(method.toLowerCase());
|
||||
}
|
||||
|
||||
const PermissionList = () => {
|
||||
let rows = [];
|
||||
|
||||
@@ -75,7 +109,8 @@ export default function AccessControlList(props) {
|
||||
</TableCell>
|
||||
{groups.map(group => <TableCell key={"perm-" + index + "-group-" + group.id} align={"center"}>
|
||||
<Checkbox checked={!permission.groups.length || permission.groups.includes(group.id)}
|
||||
disabled={permission.method.toLowerCase() === "permission/save" || !props.api.hasGroup(USER_GROUP_ADMIN)}/>
|
||||
onChange={(e) => onChangePermission(index, group.id, e.target.checked)}
|
||||
disabled={isRestricted(permission.method) || !props.api.hasGroup(USER_GROUP_ADMIN)} />
|
||||
</TableCell>)}
|
||||
</TableRow>
|
||||
);
|
||||
@@ -132,7 +167,9 @@ export default function AccessControlList(props) {
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell sx={{width: "auto"}}>{L("permission")}</TableCell>
|
||||
{ groups.map(group => <TableCell key={"group-" + group.id} align={"center"}>{group.name}</TableCell>) }
|
||||
{ groups.map(group => <TableCell key={"group-" + group.id} align={"center"}>
|
||||
{group.name}
|
||||
</TableCell>) }
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
import {Link, Navigate, useNavigate} from "react-router-dom";
|
||||
import {useCallback, useContext, useEffect, useState} from "react";
|
||||
import {LocaleContext} from "shared/locale";
|
||||
import {DataColumn, DataTable, NumericColumn, StringColumn} from "shared/elements/data-table";
|
||||
import {Button, IconButton} from "@material-ui/core";
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import {Chip} from "@mui/material";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import usePagination from "shared/hooks/pagination";
|
||||
|
||||
|
||||
export default function UserListView(props) {
|
||||
|
||||
const api = props.api;
|
||||
const showDialog = props.showDialog;
|
||||
const {translate: L, requestModules, currentLocale} = useContext(LocaleContext);
|
||||
const navigate = useNavigate();
|
||||
const pagination = usePagination();
|
||||
const [users, setUsers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
requestModules(props.api, ["general", "account"], currentLocale).then(data => {
|
||||
if (!data.success) {
|
||||
props.showDialog("Error fetching translations: " + data.msg);
|
||||
}
|
||||
});
|
||||
}, [currentLocale]);
|
||||
|
||||
const onFetchUsers = useCallback((page, count, orderBy, sortOrder) => {
|
||||
api.fetchUsers(page, count, orderBy, sortOrder).then((res) => {
|
||||
if (res.success) {
|
||||
setUsers(res.users);
|
||||
pagination.update(res.pagination);
|
||||
} else {
|
||||
showDialog(res.msg, "Error fetching users");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}, [api, showDialog]);
|
||||
|
||||
const groupColumn = (() => {
|
||||
let column = new DataColumn(L("account.groups"), "groups");
|
||||
column.renderData = (L, entry) => {
|
||||
return Object.values(entry.groups).map(group => <Chip key={"group-" + group.id} label={group.name}/>)
|
||||
}
|
||||
return column;
|
||||
})();
|
||||
|
||||
const actionColumn = (() => {
|
||||
let column = new DataColumn(L("general.actions"), null, false);
|
||||
column.renderData = (L, entry) => <>
|
||||
<IconButton size={"small"} title={L("general.edit")} onClick={() => navigate("/admin/user/" + entry.id)}>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</>
|
||||
return column;
|
||||
})();
|
||||
|
||||
const columnDefinitions = [
|
||||
new NumericColumn(L("general.id"), "id"),
|
||||
new StringColumn(L("account.username"), "name"),
|
||||
new StringColumn(L("account.email"), "email"),
|
||||
groupColumn,
|
||||
new StringColumn(L("account.full_name"), "full_name"),
|
||||
actionColumn,
|
||||
];
|
||||
|
||||
return <>
|
||||
<div className={"content-header"}>
|
||||
<div className={"container-fluid"}>
|
||||
<div className={"row mb-2"}>
|
||||
<div className={"col-sm-6"}>
|
||||
<h1 className={"m-0 text-dark"}>Users</h1>
|
||||
</div>
|
||||
<div className={"col-sm-6"}>
|
||||
<ol className={"breadcrumb float-sm-right"}>
|
||||
<li className={"breadcrumb-item"}><Link to={"/admin/dashboard"}>Home</Link></li>
|
||||
<li className="breadcrumb-item active">Users</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={"content"}>
|
||||
<div className={"container-fluid"}>
|
||||
<Link to="/admin/user/new">
|
||||
<Button variant={"outlined"} startIcon={<AddIcon />} size={"small"}>
|
||||
{L("general.create_new")}
|
||||
</Button>
|
||||
</Link>
|
||||
<DataTable
|
||||
data={users}
|
||||
pagination={pagination}
|
||||
className={"table table-striped"}
|
||||
fetchData={onFetchUsers}
|
||||
placeholder={"No users to display"}
|
||||
columns={columnDefinitions} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
@@ -77,6 +77,8 @@ export default function UserListView(props) {
|
||||
<DataTable
|
||||
data={users}
|
||||
pagination={pagination}
|
||||
defaultSortOrder={"asc"}
|
||||
defaultSortColumn={0}
|
||||
className={"table table-striped"}
|
||||
fetchData={onFetchUsers}
|
||||
placeholder={"No users to display"}
|
||||
|
||||
@@ -253,6 +253,14 @@ export default class API {
|
||||
return this.apiCall("permission/save", { permissions: permissions });
|
||||
}
|
||||
|
||||
async updatePermission(method, groups, description = null) {
|
||||
return this.apiCall("permission/update", { method: method, groups: groups, description: description });
|
||||
}
|
||||
|
||||
async deletePermission(method) {
|
||||
return this.apiCall("permission/delete", { method: method });
|
||||
}
|
||||
|
||||
/** VisitorsAPI **/
|
||||
async getVisitors(type, date) {
|
||||
return this.apiCall("visitors/stats", { type: type, date: date });
|
||||
|
||||
@@ -8,6 +8,7 @@ import clsx from "clsx";
|
||||
import {Box, IconButton, Select, TextField} from "@mui/material";
|
||||
import {formatDate, formatDateTime} from "../util";
|
||||
import CachedIcon from "@material-ui/icons/Cached";
|
||||
import {isNumber} from "chart.js/helpers";
|
||||
|
||||
|
||||
export function DataTable(props) {
|
||||
@@ -22,8 +23,8 @@ export function DataTable(props) {
|
||||
const {translate: L} = useContext(LocaleContext);
|
||||
|
||||
const [doFetchData, setFetchData] = useState(false);
|
||||
const [sortAscending, setSortAscending] = useState(["asc","ascending"].includes(defaultSortOrder?.toLowerCase));
|
||||
const [sortColumn, setSortColumn] = useState(defaultSortColumn || null);
|
||||
const [sortAscending, setSortAscending] = useState(["asc","ascending"].includes(defaultSortOrder?.toLowerCase()));
|
||||
const [sortColumn, setSortColumn] = useState(isNumber(defaultSortColumn) || null);
|
||||
const sortable = !!fetchData && (props.hasOwnProperty("sortable") ? !!props.sortable : true);
|
||||
const onRowClick = onClick || (() => {});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user