added permissions logic

This commit is contained in:
ACoolName 2024-05-23 02:08:59 +03:00
parent 39860c84e6
commit b25998da7f
3 changed files with 148 additions and 95 deletions

View File

@ -129,27 +129,6 @@ const definitions = {
], ],
title: "ImageInfo" title: "ImageInfo"
}, },
InviteUserRequests: {
properties: {
email: {
type: "string",
title: "Email"
},
permissions: {
items: {
"$ref": "#/definitions/Permission"
},
type: "array",
title: "Permissions"
}
},
type: "object",
required: [
"email",
"permissions"
],
title: "InviteUserRequests"
},
PasswordRequestForm: { PasswordRequestForm: {
properties: { properties: {
username: { username: {
@ -345,54 +324,6 @@ const definitions = {
], ],
title: "SetServerNicknameRequest" title: "SetServerNicknameRequest"
}, },
SetServerPermissionsRequest: {
properties: {
username: {
type: "string",
title: "Username",
fetch_display_path: "username",
fetch_key_path: "username",
fetch_url: "/users"
},
permissions: {
items: {
"$ref": "#/definitions/Permission"
},
type: "array",
title: "Permissions"
}
},
type: "object",
required: [
"username"
],
title: "SetServerPermissionsRequest"
},
StartServerRequest: {
properties: {
ports: {
items: {
"$ref": "#/definitions/PortMapping"
},
type: "array",
title: "Ports",
default: []
},
command: {
anyOf: [
{
type: "string"
},
{
type: "null"
}
],
title: "Command"
}
},
type: "object",
title: "StartServerRequest"
},
Token: { Token: {
properties: { properties: {
access_token: { access_token: {
@ -482,7 +413,29 @@ export const SERVER_ACTIONS: ActionInfo[] = [
{ {
name: "Start", name: "Start",
args: { args: {
"$ref": "#/definitions/StartServerRequest", properties: {
ports: {
items: {
"$ref": "#/definitions/PortMapping"
},
type: "array",
title: "Ports",
default: []
},
command: {
anyOf: [
{
type: "string"
},
{
type: "null"
}
],
title: "Command"
}
},
type: "object",
title: "Start Server",
definitions: definitions, definitions: definitions,
}, },
requestType: "post", requestType: "post",
@ -554,27 +507,66 @@ export const SERVER_ACTIONS: ActionInfo[] = [
response_action: "Browse" response_action: "Browse"
}, },
{ {
name: "Set Nickname", name: "Update Server",
requestType: "patch",
endpoint: "/servers/{server_id}",
permissions: Permission.Admin,
response_action: "Ignore",
args: { args: {
"$ref": "#/definitions/SetServerNicknameRequest", title: "Update Server",
type: "object",
required: [],
properties: {
DefaultPorts: {
type: "array",
title: "Default Ports",
items:
{
"$ref": "#/definitions/Port-Input"
}
},
DefaultCommand: {
type: "string",
title: "Default Command"
},
Nickname: {
type: "string",
title: "Nickname"
}
},
definitions: definitions, definitions: definitions,
}, },
requestType: "post",
endpoint: "/servers/{server_id}/nickname",
permissions: Permission.Admin,
response_action: "Ignore"
}, },
{ {
name: "Add Permissions", name: "Add Permissions",
args: {
"$ref": "#/definitions/SetServerPermissionsRequest",
definitions: definitions,
},
requestType: "post", requestType: "post",
endpoint: "/servers/{server_id}/permissions", endpoint: "/servers/{server_id}/permissions",
permissions: Permission.Admin, permissions: Permission.Admin,
response_action: "Ignore" response_action: "Ignore",
args: {
properties: {
username: {
type: "string",
title: "Username",
fetch_display_path: "Username",
fetch_key_path: "Username",
fetch_url: "/users"
},
permissions: {
type: "number",
title: "Permissions",
permissions: true,
}
},
type: "object",
required: [
"username"
],
title: "Set User Permissions",
definitions: definitions,
},
} }
] ]
@ -622,7 +614,22 @@ export const CREATE_SERVER_ACTION: ActionInfo = {
export const INVITE_USER_ACTION: ActionInfo = { export const INVITE_USER_ACTION: ActionInfo = {
name: "Invite User", name: "Invite User",
args: { args: {
"$ref": "#/definitions/InviteUserRequests", properties: {
email: {
type: "string",
title: "Email"
},
permissions: {
type: "number",
title: "Permissions",
permissions: true,
}
},
type: "object",
required: [
"email"
],
title: "Invite User",
definitions: definitions, definitions: definitions,
}, },
requestType: "post", requestType: "post",

View File

@ -6,8 +6,7 @@ import { Box, Button, ButtonGroup, ButtonOwnProps, Modal, PaletteMode, Paper, Ta
import { Form } from "@rjsf/mui"; import { Form } from "@rjsf/mui";
import validator from '@rjsf/validator-ajv8'; import validator from '@rjsf/validator-ajv8';
import { blue, grey } from "@mui/material/colors"; import { blue, grey } from "@mui/material/colors";
import { OpenAPISchema, User } from "./interfaces"; import { User } from "./interfaces";
import { JSONSchema7 } from "json-schema";
import { IChangeEvent } from "@rjsf/core"; import { IChangeEvent } from "@rjsf/core";
import { RJSFSchema, WidgetProps } from "@rjsf/utils"; import { RJSFSchema, WidgetProps } from "@rjsf/utils";
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
@ -99,7 +98,7 @@ export function ApiWrapper(p: { children: ReactNode}) {
export interface ActionInfo { export interface ActionInfo {
name: string name: string
requestType: 'post' | 'get' | 'delete' requestType: 'post' | 'get' | 'delete' | 'patch'
endpoint: string endpoint: string
args: {} args: {}
permissions?: number permissions?: number
@ -114,16 +113,63 @@ interface Options{
export const actionIdentifierContext: Context<string> = createContext('') export const actionIdentifierContext: Context<string> = createContext('')
function FetcherField(props: WidgetProps){
function convertNumber(permissions: number): number[]{
var arr: number[] = []
if (permissions&Permission.Start){
arr.push(Permission.Start)
}
if (permissions&Permission.Stop){
arr.push(Permission.Stop)
}
if (permissions&Permission.Browse){
arr.push(Permission.Browse)
}
if (permissions&Permission.RunCommand){
arr.push(Permission.RunCommand)
}
if (permissions&Permission.Create){
arr.push(Permission.Create)
}
if (permissions&Permission.Delete){
arr.push(Permission.Delete)
}
if (permissions&Permission.Admin){
arr.push(Permission.Admin)
}
return arr
}
function CustomField(props: WidgetProps){
const jp = require('jsonpath') const jp = require('jsonpath')
const [options2, setOptions]: [Options[]|null, Dispatch<Options[]>] = useState(null as Options[]|null) const [options2, setOptions]: [Options[]|null, Dispatch<Options[]>] = useState(null as Options[]|null)
const {schema, registry, options, ...newProps} = props const {schema, registry, options, ...newProps} = props
const {SelectWidget} = registry.widgets const {SelectWidget, CheckboxesWidget} = registry.widgets
if (!schema.fetch_url){ if (!schema.fetch_url){
if (!schema.permissions){
return <TextField onChange={(event)=>(props.onChange(event.target.value))} value={props.value} label={props.label}/> return <TextField onChange={(event)=>(props.onChange(event.target.value))} value={props.value} label={props.label}/>
} }
return <CheckboxesWidget
{...newProps}
onChange={(event)=>{
props.onChange(event.reduce((partialSum: number, a: number) => (partialSum + a), 0))
}
}
schema={{}}
options={{
enumOptions: [
{label: 'Start', value: Permission.Start},
{label: 'Stop', value: Permission.Stop},
{label: 'Browse', value: Permission.Browse},
{label: 'Delete', value: Permission.Delete},
{label: 'RunCommand', value: Permission.RunCommand},
{label: 'Create', value: Permission.Create},
{label: 'Admin', value: Permission.Admin},
]}} registry={registry} value={convertNumber(props.value)} />
}
if (options2 === null){ if (options2 === null){
api.get(schema.fetch_url as string).then((event)=>{ api.get(schema.fetch_url as string).then((event)=>{
let newOptions: Options[] = [] let newOptions: Options[] = []
@ -142,7 +188,6 @@ function FetcherField(props: WidgetProps){
function isUserAllowed(user: User|null, action: ActionInfo): boolean{ function isUserAllowed(user: User|null, action: ActionInfo): boolean{
console.log({User: user, Action: action})
if (user === null){ if (user === null){
return false return false
} }
@ -171,6 +216,7 @@ export function ActionItem(p: { action: ActionInfo, identifierSubstring?: string
const [form, setForm] = useState(false); const [form, setForm] = useState(false);
const [formData, setFormData]: [RJSFSchema, Dispatch<RJSFSchema>] = useState({}) const [formData, setFormData]: [RJSFSchema, Dispatch<RJSFSchema>] = useState({})
console.log(formData)
function handleSubmit() { function handleSubmit() {
@ -181,6 +227,10 @@ export function ActionItem(p: { action: ActionInfo, identifierSubstring?: string
promise = api.post(url, formData) promise = api.post(url, formData)
break break
} }
case 'patch':{
promise = api.patch(url, formData)
break
}
case 'get': { case 'get': {
if (formData){ if (formData){
console.warn('get can get no arguments, dropping') console.warn('get can get no arguments, dropping')
@ -218,7 +268,7 @@ export function ActionItem(p: { action: ActionInfo, identifierSubstring?: string
open={form} open={form}
> >
<Box sx={formModalStyle}> <Box sx={formModalStyle}>
<Form validator={validator} widgets={{TextWidget: FetcherField}} schema={p.action.args} onChange={onFormChange} formData={formData} onSubmit={handleSubmit} /> <Form validator={validator} widgets={{TextWidget: CustomField}} schema={p.action.args} onChange={onFormChange} formData={formData} onSubmit={handleSubmit} />
</Box> </Box>
</Modal> </Modal>
</>) </>)
@ -294,9 +344,6 @@ export function ActionGroup(p: { actions: ActionInfo[], identifierSubstring?: st
<ClickAwayListener onClickAway={handleClose}> <ClickAwayListener onClickAway={handleClose}>
<MenuList id="split-button-menu" autoFocusItem> <MenuList id="split-button-menu" autoFocusItem>
{actionItems.map((option, index) => { {actionItems.map((option, index) => {
if (!option.props){
console.log(actionItems)
}
return <MenuItem return <MenuItem
key={option.props.action.name} key={option.props.action.name}
selected={index === selectedIndex} selected={index === selectedIndex}

View File

@ -48,7 +48,6 @@ function UserItem(p: { user: User }) {
export function UsersPage({ }) { export function UsersPage({ }) {
const [apiAuthenticated, setApiAuthenticated] = useContext(apiAuthenticatedContext) const [apiAuthenticated, setApiAuthenticated] = useContext(apiAuthenticatedContext)
const [users, setUsers]: [User[], Dispatch<User[]>] = useState([] as User[]) const [users, setUsers]: [User[], Dispatch<User[]>] = useState([] as User[])
console.log({apiAuthenticated: apiAuthenticated, users: users})
const action: ActionInfo|undefined = INVITE_USER_ACTION const action: ActionInfo|undefined = INVITE_USER_ACTION
@ -60,7 +59,7 @@ export function UsersPage({ }) {
setUsers(response.data) setUsers(response.data)
}).catch( }).catch(
(error) => { (error) => {
console.log('Failed to get servers: ' + error); console.log('Failed to get users: ' + error);
if (error.response) { if (error.response) {
if (error.response.status === 401) { if (error.response.status === 401) {
setApiAuthenticated(false) setApiAuthenticated(false)