Boy132 fc643f57f9
Admin Roles (#502)
* add spatie/permissions

* add policies

* add role resource

* add root admin role handling

* replace some "root_admin" with function

* add model specific permissions

* make permission selection nicer

* fix user creation

* fix tests

* add back subuser checks in server policy

* add custom model for role

* assign new users to role if root_admin is set

* add api for roles

* fix phpstan

* add permissions for settings page

* remove "restore" and "forceDelete" permissions

* add user count to list

* prevent deletion if role has users

* update user list

* fix server policy

* remove old `root_admin` column

* small refactor

* fix tests

* forgot can checks here

* forgot use

* disable editing own roles & disable assigning root admin

* don't allow to rename root admin role

* remove php bombing exception handler

* fix role assignment when creating a user

* fix disableOptionWhen

* fix missing `root_admin` attribute on react frontend

* add permission check for bulk delete

* rename viewAny to viewList

* improve canAccessPanel check

* fix admin not displaying for non-root admins

* make sure non root admins can't edit root admins

* fix import

* fix settings page permission check

* fix server permissions for non-subusers

* fix settings page permission check v2

* small cleanup

* cleanup config file

* move consts from resouce into enum & model

* Update database/migrations/2024_08_01_114538_remove_root_admin_column.php

Co-authored-by: Lance Pioch <lancepioch@gmail.com>

* fix config

* fix phpstan

* fix phpstan 2.0

---------

Co-authored-by: Lance Pioch <lancepioch@gmail.com>
2024-09-21 12:27:41 +02:00

98 lines
3.7 KiB
TypeScript

import React, { lazy } from 'react';
import { hot } from 'react-hot-loader/root';
import { Route, Router, Switch } from 'react-router-dom';
import { StoreProvider } from 'easy-peasy';
import { store } from '@/state';
import { SiteSettings } from '@/state/settings';
import ProgressBar from '@/components/elements/ProgressBar';
import { NotFound } from '@/components/elements/ScreenBlock';
import tw from 'twin.macro';
import GlobalStylesheet from '@/assets/css/GlobalStylesheet';
import { history } from '@/components/history';
import { setupInterceptors } from '@/api/interceptors';
import AuthenticatedRoute from '@/components/elements/AuthenticatedRoute';
import { ServerContext } from '@/state/server';
import '@/assets/tailwind.css';
import Spinner from '@/components/elements/Spinner';
const DashboardRouter = lazy(() => import(/* webpackChunkName: "dashboard" */ '@/routers/DashboardRouter'));
const ServerRouter = lazy(() => import(/* webpackChunkName: "server" */ '@/routers/ServerRouter'));
const AuthenticationRouter = lazy(() => import(/* webpackChunkName: "auth" */ '@/routers/AuthenticationRouter'));
interface ExtendedWindow extends Window {
SiteConfiguration?: SiteSettings;
PanelUser?: {
uuid: string;
username: string;
email: string;
/* eslint-disable camelcase */
root_admin: boolean;
admin: boolean;
use_totp: boolean;
language: string;
updated_at: string;
created_at: string;
/* eslint-enable camelcase */
};
}
setupInterceptors(history);
const App = () => {
const { PanelUser, SiteConfiguration } = window as ExtendedWindow;
if (PanelUser && !store.getState().user.data) {
store.getActions().user.setUserData({
uuid: PanelUser.uuid,
username: PanelUser.username,
email: PanelUser.email,
language: PanelUser.language,
rootAdmin: PanelUser.root_admin,
admin: PanelUser.admin,
useTotp: PanelUser.use_totp,
createdAt: new Date(PanelUser.created_at),
updatedAt: new Date(PanelUser.updated_at),
});
}
if (!store.getState().settings.data) {
store.getActions().settings.setSettings(SiteConfiguration!);
}
return (
<>
<GlobalStylesheet />
<StoreProvider store={store}>
<ProgressBar />
<div css={tw`mx-auto w-auto`}>
<Router history={history}>
<Switch>
<Route path={'/auth'}>
<Spinner.Suspense>
<AuthenticationRouter />
</Spinner.Suspense>
</Route>
<AuthenticatedRoute path={'/server/:id'}>
<Spinner.Suspense>
<ServerContext.Provider>
<ServerRouter />
</ServerContext.Provider>
</Spinner.Suspense>
</AuthenticatedRoute>
<AuthenticatedRoute path={'/'}>
<Spinner.Suspense>
<DashboardRouter />
</Spinner.Suspense>
</AuthenticatedRoute>
<Route path={'*'}>
<NotFound />
</Route>
</Switch>
</Router>
</div>
</StoreProvider>
</>
);
};
export default hot(App);