From 7d84ed7f9ea2e9e9eb50fa32f1e3e87548e8a0af Mon Sep 17 00:00:00 2001 From: grimhilt Date: Tue, 8 Aug 2023 14:17:37 +0200 Subject: [PATCH] create and display users --- src/components/app-router.jsx | 2 + src/components/header.jsx | 1 + src/pages/users/create.jsx | 125 ++++++++++++++++++++++++++++++++ src/pages/users/index.jsx | 75 +++++++++++++++++++ src/pages/users/users-table.jsx | 40 ++++++++++ src/services/api.js | 11 ++- src/tools/grant-access.jsx | 32 ++++---- 7 files changed, 272 insertions(+), 14 deletions(-) create mode 100644 src/pages/users/create.jsx create mode 100644 src/pages/users/index.jsx create mode 100644 src/pages/users/users-table.jsx diff --git a/src/components/app-router.jsx b/src/components/app-router.jsx index 8f320b0..26b755d 100644 --- a/src/components/app-router.jsx +++ b/src/components/app-router.jsx @@ -7,6 +7,7 @@ import Playlist from '../pages/playlist'; import Files from '../pages/files'; import Authentication from '../pages/auth'; import { LoginRequired } from '../tools/grant-access'; +import Users from '../pages/users'; const AppRouter = () => { return ( @@ -16,6 +17,7 @@ const AppRouter = () => { } />} /> } />} /> } />} /> + } />} /> } /> } /> diff --git a/src/components/header.jsx b/src/components/header.jsx index 9bb376a..0562b68 100644 --- a/src/components/header.jsx +++ b/src/components/header.jsx @@ -50,6 +50,7 @@ const links = [ { label: 'Playlists', link: '/playlists' }, { label: 'Files', link: '/files' }, { label: 'Planning', link: '/planning' }, + { label: 'Users', link: '/users' }, ]; const HeaderSearch = () => { diff --git a/src/pages/users/create.jsx b/src/pages/users/create.jsx new file mode 100644 index 0000000..d4b81dd --- /dev/null +++ b/src/pages/users/create.jsx @@ -0,0 +1,125 @@ +import { Button, Group, Modal, Stack, PasswordInput, Switch, Text, TextInput, Paper } from '@mantine/core'; +import { isNotEmpty, useForm } from '@mantine/form'; +import { useState } from 'react'; +import { Perm, checkPerm } from '../../tools/grant-access'; +import { useAuth } from '../../tools/auth-provider'; +import setNotification from '../errors/error-notification'; + +const ModalCreateUser = ({ opened, handler, addUser, APICall, item }) => { + const [isLoading, setIsLoading] = useState(false); + const { user } = useAuth(); + const handleClose = (item) => { + if (item) { + addUser(item); + } + handler(); + }; + + const form = useForm({ + initialValues: { + login: '', + password: '', + create_user: false, + create_role: false, + create_playlist: false, + }, + validate: { + login: isNotEmpty('Login is required'), + password: isNotEmpty('Password is required'), + }, + }); + + const handleSubmit = async (event) => { + event.preventDefault(); + if (form.validate().hasErrors) return; + try { + setIsLoading(true); + if (item) { + // await APICall(item?.id, { name: form.values.name }); + // item.name = form.values.name; + handleClose(item); + } else { + let data = { login: form.values.login, password: form.values.password }; + data.permissions = 0; + if (form.values.create_user) data.permissions += 1; + if (form.values.create_role) data.permissions += 2; + if (form.values.create_playlist) data.permissions += 4; + const res = await APICall(data); + handleClose(res.data); + } + setIsLoading(false); + } catch (err) { + setIsLoading(false); + setNotification(true, err); + } + }; + + // todo parent role + + return ( + + + + + + + Create User + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+
+
+ ); +}; + +export default ModalCreateUser; diff --git a/src/pages/users/index.jsx b/src/pages/users/index.jsx new file mode 100644 index 0000000..22da0b0 --- /dev/null +++ b/src/pages/users/index.jsx @@ -0,0 +1,75 @@ +import { useEffect, useState } from 'react'; +import NavbarSignage from '../../components/navbar'; +import API from '../../services/api'; +import setNotification from '../errors/error-notification'; +import ModalCreateUser from './create'; +import { Button } from '@mantine/core'; +import GrantAccess, { Perm } from '../../tools/grant-access'; +import UserTable from './users-table'; + +const Users = () => { + const [showCreate, setShowCreate] = useState(true); + const [showUpdate, setShowUpdate] = useState(false); + + const toggleModalCreate = () => setShowCreate(!showCreate); + const toggleModalUpdate = () => setShowUpdate(!showUpdate); + + const [users, setUsers] = useState([]); + const [roles, setRoles] = useState([]); + + useEffect(() => { + API.listUsers() + .then((res) => { + if (res.status === 200) { + if (users.length === 0) setUsers(res.data); + else setUsers((prev) => [...prev, ...res.data]); + } + }) + .catch((err) => { + setNotification(true, err); + }); + API.listRoles() + .then((res) => { + if (res.status === 200) { + if (roles.length === 0) setRoles(res.data); + else setRoles((prev) => [...prev, ...res.data]); + } + }) + .catch((err) => { + setNotification(true, err); + }); + + return () => {}; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const [search, setSearch] = useState(''); + + const addUser = (user) => { + setUsers((prev) => [...prev, user]); + }; + + const navbar = { + title: 'Users', + search: search, + handlerChange: (e) => setSearch(e.target.value), + buttonCreate: ( + New User} /> + ), + }; + + return ( + <> + + setUsers(users.filter((item) => item.id != id))} + updateHandler={toggleModalUpdate} + /> + addUser(user)} APICall={API.createUser} /> + + ); +}; + +export default Users; diff --git a/src/pages/users/users-table.jsx b/src/pages/users/users-table.jsx new file mode 100644 index 0000000..2955d9f --- /dev/null +++ b/src/pages/users/users-table.jsx @@ -0,0 +1,40 @@ +import { Button, Center, Table, Paper, ScrollArea, Group } from '@mantine/core'; +import { useNavigate } from 'react-router-dom'; + +const UserTable = (props) => { + const rows = props.data.map((user) => ( + + {user.login} + + + + + + + + + )); + + return ( + + + + + + + + + + {rows} +
NameActions
+
+
+ +
+
+ ); +}; + +export default UserTable; diff --git a/src/services/api.js b/src/services/api.js index 14687fa..927684e 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -16,6 +16,12 @@ const API = { login(data) { return caller().post('/auth/login', data); }, + listUsers(data) { + return caller().get('/users', data); + }, + listRoles(data) { + return caller().get('/roles', data); + }, listPlaylists(data) { return caller().get('/playlists', data); }, @@ -23,7 +29,7 @@ const API = { return caller().post('/playlists', data); }, updatePlaylist(playlistId, data) { - return caller().post(`/playlists/${playlistId}/update`, data); + return caller().put(`/playlists/${playlistId}/update`, data); }, activate(playlistId) { return caller().post(`/playlists/${playlistId}/activate`); @@ -52,6 +58,9 @@ const API = { playlistRemoveFile(playlistId, data) { return caller().post(`/playlists/${playlistId}/remove_file`, data); }, + createUser(data) { + return caller().post('/users', data); + }, }; export default API; diff --git a/src/tools/grant-access.jsx b/src/tools/grant-access.jsx index 2037266..8f2ca61 100644 --- a/src/tools/grant-access.jsx +++ b/src/tools/grant-access.jsx @@ -1,24 +1,30 @@ import { useAuth } from './auth-provider'; import Authentication from '../pages/auth'; -import { useEffect } from 'react'; export const Perm = { - CREATE_ROLE: 0, - CREATE_PLAYLIST: 1, - VIEW_PLAYLIST: 2, - OWN_PLAYLIST: 3, - EDIT_PLAYLIST: 4, - ACTIVATE_PLAYLIST: 5, + CREATE_USER: 1, + CREATE_ROLE: 2, + CREATE_PLAYLIST: 3, + VIEW_PLAYLIST: 4, + OWN_PLAYLIST: 5, + EDIT_PLAYLIST: 6, + ACTIVATE_PLAYLIST: 7, }; -const checkPerm = (perm, user, item = {}) => { - console.log(user); - console.log(item); +const checkBit = (dec, perm) => { + const binStr = (dec >>> 0).toString(2); + const len = binStr.length; + return binStr[len - perm - 1]; +}; + +export const checkPerm = (perm, user, item = {}) => { switch (perm) { case Perm.CREATE_ROLE: - return false; + return user.roles.length >= 1 && checkBit(user.roles[0].permissions, Perm.CREATE_ROLE); case Perm.CREATE_PLAYLIST: - return user.roles.findIndex((role) => role.can_create_playlist) !== -1; + return user.roles.length >= 1 && checkBit(user.roles[0].permissions, Perm.CREATE_PLAYLIST); + case Perm.CREATE_ROLE: + return user.roles.length >= 1 && checkBit(user.roles[0].permissions, Perm.CREATE_USER); case Perm.OWN_PLAYLIST: return item?.owner_id === user.id; default: @@ -28,7 +34,7 @@ const checkPerm = (perm, user, item = {}) => { const GrantAccess = ({ role, roles, children, item }) => { const { user } = useAuth(); - if (role && checkPerm(role, user, item)) { + if (role && checkPerm(role, user)) { return children; } else if (roles) { let flag = false;