Skip to content
This repository has been archived by the owner on Dec 18, 2023. It is now read-only.

Commit

Permalink
Allow paritytech member to see resources
Browse files Browse the repository at this point in the history
  • Loading branch information
jeluard committed Feb 22, 2021
1 parent ce0a16e commit 43b33a6
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 66 deletions.
24 changes: 12 additions & 12 deletions backend/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub fn get_user(
id: String,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_read_rights() {
Ok(result_to_jsonrpc(manager.get_user(&id)))
} else {
Err(status::Unauthorized::<()>(None))
Expand All @@ -135,7 +135,7 @@ pub fn list_users(
user: LoggedUser,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_read_rights() {
Ok(result_to_jsonrpc(manager.list_users()))
} else {
Err(status::Unauthorized::<()>(None))
Expand All @@ -150,7 +150,7 @@ pub fn create_user(
conf: Json<UserConfiguration>,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_edit_rights() {
Ok(result_to_jsonrpc(manager.create_user(id, conf.0)))
} else {
Err(status::Unauthorized::<()>(None))
Expand All @@ -165,7 +165,7 @@ pub fn update_user(
conf: Json<UserUpdateConfiguration>,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_edit_rights() {
Ok(result_to_jsonrpc(manager.update_user(id, conf.0)))
} else {
Err(status::Unauthorized::<()>(None))
Expand All @@ -179,7 +179,7 @@ pub fn delete_user(
id: String,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_edit_rights() {
Ok(result_to_jsonrpc(manager.delete_user(id)))
} else {
Err(status::Unauthorized::<()>(None))
Expand Down Expand Up @@ -253,7 +253,7 @@ pub fn get_session(
id: String,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_read_rights() {
Ok(result_to_jsonrpc(manager.get_session(&id)))
} else {
Err(status::Unauthorized::<()>(None))
Expand All @@ -266,7 +266,7 @@ pub fn list_sessions(
user: LoggedUser,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_read_rights() {
Ok(result_to_jsonrpc(manager.list_sessions()))
} else {
Err(status::Unauthorized::<()>(None))
Expand All @@ -281,7 +281,7 @@ pub fn create_session(
conf: Json<SessionConfiguration>,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_edit_rights() {
Ok(result_to_jsonrpc(
manager.create_session(&id, &user, conf.0),
))
Expand All @@ -298,7 +298,7 @@ pub fn update_session(
conf: Json<SessionUpdateConfiguration>,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_edit_rights() {
Ok(result_to_jsonrpc(
manager.update_session(&id, &user, conf.0),
))
Expand All @@ -314,7 +314,7 @@ pub fn delete_session(
id: String,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_edit_rights() {
Ok(result_to_jsonrpc(manager.delete_session(&id)))
} else {
Err(status::Unauthorized::<()>(None))
Expand All @@ -330,7 +330,7 @@ pub fn get_pool(
id: String,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_read_rights() {
Ok(result_to_jsonrpc(manager.get_pool(&id)))
} else {
Err(status::Unauthorized::<()>(None))
Expand All @@ -343,7 +343,7 @@ pub fn list_pools(
user: LoggedUser,
) -> Result<JsonValue, status::Unauthorized<()>> {
let manager = state.manager.clone();
if user.admin {
if user.has_admin_read_rights() {
Ok(result_to_jsonrpc(manager.list_pools()))
} else {
Err(status::Unauthorized::<()>(None))
Expand Down
17 changes: 3 additions & 14 deletions backend/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,17 +206,6 @@ impl Manager {
new_runtime()?.block_on(self.clone().engine.list_sessions())
}

fn paritytech_member(&self, user: &LoggedUser) -> bool {
user.organizations.contains(&"paritytech".to_string())
}
fn can_customize_duration(&self, user: &LoggedUser) -> bool {
user.admin || user.can_customize_duration || self.paritytech_member(user)
}

fn can_customize_pool_affinity(&self, user: &LoggedUser) -> bool {
user.admin || user.can_customize_pool_affinity || self.paritytech_member(user)
}

pub fn create_session(
self,
id: &str,
Expand All @@ -225,13 +214,13 @@ impl Manager {
) -> Result<(), String> {
if conf.duration.is_some() {
// Duration can only customized by users with proper rights
if !self.can_customize_duration(user) {
if !user.can_customize_duration() {
return Err("Only admin can customize a session duration".to_string());
}
}
if conf.pool_affinity.is_some() {
// Duration can only customized by users with proper rights
if !self.can_customize_pool_affinity(user) {
if !user.can_customize_pool_affinity() {
return Err("Only admin can customize a session pool affinity".to_string());
}
}
Expand Down Expand Up @@ -261,7 +250,7 @@ impl Manager {
) -> Result<(), String> {
if conf.duration.is_some() {
// Duration can only customized by users with proper rights
if !self.can_customize_duration(user) {
if !user.can_customize_duration() {
return Err("Only admin can customize a session duration".to_string());
}
}
Expand Down
23 changes: 23 additions & 0 deletions backend/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,29 @@ pub struct LoggedUser {
pub can_customize_pool_affinity: bool,
}

impl LoggedUser {

pub fn is_paritytech_member(&self) -> bool {
self.organizations.contains(&"paritytech".to_string())
}
pub fn can_customize_duration(&self) -> bool {
self.admin || self.can_customize_duration || self.is_paritytech_member()
}

pub fn can_customize_pool_affinity(&self) -> bool {
self.admin || self.can_customize_pool_affinity || self.is_paritytech_member()
}

pub fn has_admin_read_rights(&self) -> bool {
self.admin || self.is_paritytech_member()
}

pub fn has_admin_edit_rights(&self) -> bool {
self.admin
}

}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Template {
pub name: String,
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Typography from '@material-ui/core/Typography';
import { Configuration, LoggedUser } from "@substrate/playground-client";
import { useInterval } from './hooks';
import { Params } from "./index";
import { hasAdminReadRights } from './utils';

function wrapAction(action: (() => void) | Promise<void>, call: (flag: boolean) => void):(() => void) | Promise<void> {
if (action instanceof Promise) {
Expand Down Expand Up @@ -156,7 +157,7 @@ function Nav({ conf, onPlayground, onStatsClick, onAdminClick, onLogout, user }:
<Button onClick={onPlayground}>Playground</Button>
</Typography>
<div style={{display: "flex", alignItems: "center"}}>
{user?.admin &&
{(user && hasAdminReadRights(user)) &&
<div style={{paddingLeft: 12}}>
<IconButton
aria-label="account of current user"
Expand Down
75 changes: 37 additions & 38 deletions frontend/src/panels/admin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import Typography from '@material-ui/core/Typography';
import { Client, Configuration, LoggedUser, Pool, Session, SessionConfiguration, SessionUpdateConfiguration, Template, User, UserConfiguration, UserUpdateConfiguration } from '@substrate/playground-client';
import { CenteredContainer, ErrorSnackbar, LoadingPanel } from '../components';
import { useInterval } from '../hooks';
import { canCustomizeDuration, canCustomizePoolAffinity, hasAdminEditRights, hasAdminReadRights } from '../utils';
import { DialogActions, DialogContentText, MenuItem } from '@material-ui/core';
import { Autocomplete } from '@material-ui/lab';

Expand All @@ -38,12 +39,12 @@ const useStyles = makeStyles({
},
});

function NoResourcesContainer({ label, action }: { label: string, action?: () => void}): JSX.Element {
function NoResourcesContainer({ user, label, action }: { user: LoggedUser, label: string, action?: () => void}): JSX.Element {
return (
<Container>
<Typography variant="h6">
{label}
{action &&
{(action && hasAdminEditRights(user)) &&
<Tooltip title="Create">
<IconButton aria-label="create" onClick={action}>
<AddIcon />
Expand Down Expand Up @@ -77,18 +78,6 @@ function Resources<T>( { children, label, callback }: { children: (resources: Re
}
}

function paritytechMember(user: LoggedUser): boolean {
return user.organizations.indexOf('paritytech') != -1;
}

function canCustomizeDuration(user: LoggedUser): boolean {
return user.admin || user.canCustomizeDuration || paritytechMember(user);
}

function canCustomizePoolAffinity(user: LoggedUser): boolean {
return user.admin || user.canCustomizePoolAffinity || paritytechMember(user);
}

export function canCustomize(user: LoggedUser): boolean {
return canCustomizeDuration(user) || canCustomizePoolAffinity(user);
}
Expand Down Expand Up @@ -327,7 +316,7 @@ function Sessions({ client, conf, user }: { client: Client, conf: Configuration,
{Object.keys(resources).length > 0
?
<>
<EnhancedTableToolbar label="Sessions" selected={selected} onCreate={() => setShowCreationDialog(true)} onUpdate={() => setShowUpdateDialog(true)} onDelete={() => onDelete(setSessions)} />
<EnhancedTableToolbar user={user} label="Sessions" selected={selected} onCreate={() => setShowCreationDialog(true)} onUpdate={() => setShowUpdateDialog(true)} onDelete={() => onDelete(setSessions)} />
<TableContainer component={Paper}>
<Table className={classes.table} aria-label="simple table">
<TableHead>
Expand Down Expand Up @@ -374,7 +363,7 @@ function Sessions({ client, conf, user }: { client: Client, conf: Configuration,
</Table>
</TableContainer>
</>
: <NoResourcesContainer label={`No sessions`} action={() => setShowCreationDialog(true)} />}
: <NoResourcesContainer user={user} label="No sessions" action={() => setShowCreationDialog(true)} />}
{errorMessage &&
<ErrorSnackbar open={true} message={errorMessage} onClose={() => setErrorMessage(null)} />}
<SessionCreationDialog allowUserSelection={true} client={client} conf={conf} sessions={resources} user={user} users={users} templates={templates} show={showCreationDialog} onCreate={(conf, id) => onCreate(conf, id, setSessions)} onHide={() => setShowCreationDialog(false)} />
Expand All @@ -386,14 +375,14 @@ function Sessions({ client, conf, user }: { client: Client, conf: Configuration,
);
}

function Templates({ client }: { client: Client }): JSX.Element {
function Templates({ client, user }: { client: Client, user: LoggedUser }): JSX.Element {
const classes = useStyles();

return (
<Resources<Template> label="Templates" callback={async () => (await client.get()).templates}>
{(resources: Record<string, Template>) => (
<>
<EnhancedTableToolbar label="Templates" />
<EnhancedTableToolbar user={user} label="Templates" />
<TableContainer component={Paper}>
<Table className={classes.table} aria-label="simple table">
<TableHead>
Expand Down Expand Up @@ -474,20 +463,10 @@ function DeleteConfirmationDialog({open, onClose, onConfirmation}: {open: boolea
);
}

function EnhancedTableToolbar({ label, selected = null, onCreate, onUpdate, onDelete }: { label: string, selected?: string | null, onCreate?: () => void, onUpdate?: () => void, onDelete?: () => void}): JSX.Element {
function EditToolbar({ selected, onCreate, onUpdate, onDelete }: {selected?: string | null, onCreate?: () => void, onUpdate?: () => void, onDelete?: () => void}): JSX.Element {
const [open, setOpen] = React.useState(false);
const classes = useToolbarStyles();
return (
<>
<Toolbar
className={clsx(classes.root, {
[classes.highlight]: selected != null,
})}
>
<Typography className={classes.title} variant="h6" id="tableTitle" component="div">
{label}
</Typography>
{selected ?
if (selected) {
return (
<>
{onUpdate &&
<Tooltip title="Update">
Expand All @@ -503,15 +482,35 @@ function EnhancedTableToolbar({ label, selected = null, onCreate, onUpdate, onDe
</Tooltip>}
<DeleteConfirmationDialog open={open} onClose={() => setOpen(false)} onConfirmation={onDelete} />
</>
: <>
);
} else {
return (
<>
{onCreate &&
<Tooltip title="Create">
<IconButton aria-label="create" onClick={onCreate}>
<AddIcon />
</IconButton>
</Tooltip>}
</>
}
);
}
}

function EnhancedTableToolbar({ user, label, selected = null, onCreate, onUpdate, onDelete }: { user: LoggedUser, label: string, selected?: string | null, onCreate?: () => void, onUpdate?: () => void, onDelete?: () => void}): JSX.Element {
const classes = useToolbarStyles();
return (
<>
<Toolbar
className={clsx(classes.root, {
[classes.highlight]: selected != null,
})}
>
<Typography className={classes.title} variant="h6" id="tableTitle" component="div">
{label}
</Typography>
{hasAdminEditRights(user) &&
<EditToolbar selected={selected} onCreate={onCreate} onUpdate={onUpdate} onDelete={onDelete} />}
</Toolbar>
</>
);
Expand Down Expand Up @@ -747,7 +746,7 @@ function Users({ client, user, conf }: { client: Client, user: LoggedUser, conf:
<Resources<User> label="Users" callback={async () => await client.listUsers()}>
{(resources: Record<string, User>, setUsers: Dispatch<SetStateAction<Record<string, User> | null>>) => (
<>
<EnhancedTableToolbar label="Users" selected={selected} onCreate={() => setShowCreationDialog(true)} onUpdate={() => setShowUpdateDialog(true)} onDelete={() => onDelete(setUsers)} />
<EnhancedTableToolbar user={user} label="Users" selected={selected} onCreate={() => setShowCreationDialog(true)} onUpdate={() => setShowUpdateDialog(true)} onDelete={() => onDelete(setUsers)} />
<TableContainer component={Paper}>
<Table className={classes.table} aria-label="simple table">
<TableHead>
Expand Down Expand Up @@ -839,14 +838,14 @@ function DetailsPanel({ conf }: { conf: Configuration }): JSX.Element {
);
}

function Pools({ client }: { client: Client }): JSX.Element {
function Pools({ client, user }: { client: Client, user: LoggedUser }): JSX.Element {
const classes = useStyles();

return (
<Resources<Pool> label="Pools" callback={async () => await client.listPools()}>
{(resources: Record<string, Pool>) => (
<>
<EnhancedTableToolbar label="Pools" />
<EnhancedTableToolbar user={user} label="Pools" />
<TableContainer component={Paper}>
<Table className={classes.table} aria-label="simple table">
<TableHead>
Expand Down Expand Up @@ -894,12 +893,12 @@ export function AdminPanel({ client, user, conf }: { client: Client, user: Logge
{value == 0
? <DetailsPanel conf={conf} />
: value == 1
? <Templates client={client} />
? <Templates client={client} user={user} />
: value == 2
? <Users client={client} user={user} conf={conf} />
: value == 3
? <Sessions client={client} conf={conf} user={user} />
: <Pools client={client} />}
: <Pools client={client} user={user} />}
</Paper>
</CenteredContainer>
);
Expand Down
Loading

0 comments on commit 43b33a6

Please sign in to comment.