bugfix, permission api rewrite

This commit is contained in:
2024-03-27 15:15:46 +01:00
parent ee638914a8
commit aa51380055
11 changed files with 365 additions and 182 deletions

View File

@@ -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>

View File

@@ -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>
</>
}

View File

@@ -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"}

View File

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

View File

@@ -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 || (() => {});