Skip to content

Commit

Permalink
Merge main into branch
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasMGo committed Nov 21, 2023
2 parents b896007 + 8ae762f commit 96ee1ae
Show file tree
Hide file tree
Showing 92 changed files with 5,818 additions and 3,015 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,18 @@ _Server version:_ If successful, this automatically starts a Chrome/Chromium bro
**Authentication & Authorization**

The API (`yarn dev-ms`) creates two users when it starts:
When you start the API with `yarn dev-ms-api`, you can log in with two default users just by typing their name in the 'Sign in with Development Users' section:

- Admin: With the username `admin`.
- John Doe: With the username `johndoe`.

Additionaly, if you have set up the environments folder in `src/management-system/src/backend/server/environment-configurations/` and `useAuth0` is set to `true` these two default users are created in the development Auth0 environment.

- Admin: With the username `admin` and the password `ProceedAdm1n!`.
- John Doe: With the username `johndoe` and the password `JohnDoe1!`.

> :warning: To use `yarn dev-ms-api-auth0` you need access to the private environments repository.
## Testing

Before committing a new version, a linting check is automatically done.
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@
"dev-ms": "cd src/management-system-v2 && cross-env USE_AUTHORIZATION=true yarn dev",
"dev-ms-api-no-iam": "cd src/management-system && cross-env process.env.API_ONLY=true USE_AUTHORIZATION=false yarn web:dev-start-backend",
"dev-ms-api": "cd src/management-system && cross-env process.env.API_ONLY=true yarn web:dev-iam",
"dev-ms-api-auth0": "cd src/management-system && cross-env process.env.API_ONLY=true process.env.USE_AUTH0=true yarn web:dev-iam",
"dev-ms-old": "cd src/management-system && yarn web:dev",
"dev-ms-old-iam": "cd src/management-system && yarn web:dev-iam",
"dev-web": "yarn build && cd src/engine/native/web/server && yarn serve",
"dev-many": "node src/engine/e2e_tests/process/deployment/startEngines.js",
"build": "cd src/engine/native/node && webpack --config webpack.native.config.js && webpack --config webpack.injector.config.ts && node --loader ts-node/esm ./build-injector.js && cd ../../universal && webpack --config webpack.universal.config.js",
"build-ms-web": "cd src/management-system && yarn web:build-server-frontend",
"build-ms-server": "cd src/management-system && yarn web:build-server && cd ../.. && cp -r src/management-system-v2 build/management-system/server/management-system-v2 && cp -r src/helper-modules build/management-system/server/management-system-v2/helper-modules",
"build-ms-server": "cd src/management-system && yarn web:build-server && cd .. && cd management-system-v2 && yarn build && cp -r .next/standalone ../../build/management-system/server/v2",
"build-web": "yarn build && cd src/engine/native/web/server && yarn build",
"docker:run": "docker container run --publish 33029:33029 --rm --network host --detach --name engine proceed/engine:latest",
"docker:stop": "docker container stop engine",
Expand Down
7 changes: 7 additions & 0 deletions src/management-system-v2/.env.local.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
NEXTAUTH_URL=
NEXTAUTH_SECRET=

AUTH0_CLIENT_ID=
AUTH0_CLIENT_SECRET=
AUTH0_ISSUER=
AUTH0_SCOPE=
Original file line number Diff line number Diff line change
@@ -1,68 +1,5 @@
'use client';

import Content from '@/components/content';
import Auth from '@/lib/AuthCanWrapper';
import { useGetAsset } from '@/lib/fetch-data';
import { Button, Result, Skeleton, Space, Tabs } from 'antd';
import { LeftOutlined } from '@ant-design/icons';
import { ComponentProps } from 'react';
import RoleGeneralData from './roleGeneralData';
import { useRouter } from 'next/navigation';
import RolePermissions from './rolePermissions';
import RoleMembers from './role-members';

type Items = ComponentProps<typeof Tabs>['items'];

function RolePage({ params: { roleId } }: { params: { roleId: string } }) {
const router = useRouter();
const {
data: role,
isLoading,
error,
} = useGetAsset('/roles/{id}', {
params: { path: { id: roleId } },
});

const items: Items = role
? [
{
key: 'members',
label: 'Manage Members',
children: <RoleMembers role={role} isLoadingRole={isLoading} />,
},
{ key: 'permissions', label: 'Permissions', children: <RolePermissions role={role} /> },
{
key: 'generalData',
label: 'General Data',
children: <RoleGeneralData roleId={roleId} />,
},
]
: [];

if (error) return;
<Result
status="error"
title="Failed to fetch role"
subTitle="An error ocurred while fetching role, please try again."
/>;

return (
<Content
title={
<Space>
<Button icon={<LeftOutlined />} onClick={() => router.push('/iam/roles')} type="text">
Back
</Button>
{role?.name}
</Space>
}
>
<Skeleton loading={isLoading}>
<Tabs items={items} />
</Skeleton>
</Content>
);
}
import Auth from '@/lib/serverAuthComponents';
import RolePage from './role-page';

export default Auth(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const RoleMembers: FC<{ role: Role; isLoadingRole?: boolean }> = ({ role, isLoad
await Promise.allSettled(
userIds.map((userId) =>
deleteUser({
parseAs: 'text',
params: { path: { roleId: role.id, userId: userId } },
}),
),
Expand Down Expand Up @@ -143,7 +144,7 @@ const RoleMembers: FC<{ role: Role; isLoadingRole?: boolean }> = ({ role, isLoad
)}
searchBarRightNode={
<Button type="primary" onClick={() => setAddUserModalOpen(true)}>
Add member
Add Member
</Button>
}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'use client';

import Content from '@/components/content';
import { useGetAsset } from '@/lib/fetch-data';
import { Button, Result, Skeleton, Space, Tabs } from 'antd';
import { LeftOutlined } from '@ant-design/icons';
import { ComponentProps } from 'react';
import RoleGeneralData from './roleGeneralData';
import { useRouter } from 'next/navigation';
import RolePermissions from './rolePermissions';
import RoleMembers from './role-members';

type Items = ComponentProps<typeof Tabs>['items'];

function RolePage({ params: { roleId } }: { params: { roleId: string } }) {
const router = useRouter();
const {
data: role,
isLoading,
error,
} = useGetAsset('/roles/{id}', {
params: { path: { id: roleId } },
});

const items: Items = role
? [
{
key: 'generalData',
label: 'General Data',
children: <RoleGeneralData roleId={roleId} />,
},
{ key: 'permissions', label: 'Permissions', children: <RolePermissions role={role} /> },
{
key: 'members',
label: 'Manage Members',
children: <RoleMembers role={role} isLoadingRole={isLoading} />,
},
]
: [];

if (error)
return (
<Result
status="error"
title="Failed to fetch role"
subTitle="An error ocurred while fetching role, please try again."
/>
);

return (
<Content
title={
<Space>
<Button icon={<LeftOutlined />} onClick={() => router.push('/iam/roles')} type="text">
Back
</Button>
{role?.name}
</Space>
}
>
<div style={{ maxWidth: '800px', margin: 'auto' }}>
<Skeleton loading={isLoading}>
<Tabs items={items} />
</Skeleton>
</div>
</Content>
);
}

export default RolePage;
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Ability from '@/lib/ability/abilityHelper';
import { ResourceActionType } from '@/lib/ability/caslAbility';
import { ApiData } from '@/lib/fetch-data';

type Role = ApiData<'/roles', 'get'>[number];

// permission mapping to verbs
const PERMISSION_MAPPING = {
none: 0,
view: 1,
update: 2,
create: 4,
delete: 8,
manage: 16,
share: 32,
'manage-roles': 64,
'manage-groups': 128,
'manage-password': 256,
admin: 9007199254740991,
} as const;

export function togglePermission(
permissions: Role['permissions'],
resource: keyof Role['permissions'],
permission: keyof typeof PERMISSION_MAPPING,
) {
const currentValue = permissions[resource] ?? 0;

if (permission !== 'admin') {
const permissionBit = PERMISSION_MAPPING[permission];
permissions[resource] = currentValue ^ permissionBit;
} else {
permissions[resource] =
currentValue === PERMISSION_MAPPING.admin ? 0 : PERMISSION_MAPPING.admin;
}

// New pointer for role object to trigger a rerender
return { ...permissions };
}

export function switchChecked(
permissions: Role['permissions'] | undefined,
resource: keyof Role['permissions'],
action: ResourceActionType,
) {
if (!(permissions !== undefined && typeof permissions === 'object' && resource in permissions))
return false;

const permissionNumber = permissions[resource]!;

if (action === 'admin') return permissionNumber === PERMISSION_MAPPING.admin;
else if (permissionNumber === PERMISSION_MAPPING.admin) return false;

return !!(PERMISSION_MAPPING[action] & permissionNumber);
}

export function switchDisabled(
permissions: Role['permissions'] | undefined,
resource: keyof Role['permissions'],
action: ResourceActionType,
ability: Ability,
) {
if (action === 'admin' && !ability.can('admin', resource)) return true;

if (!(permissions !== undefined && typeof permissions === 'object' && resource in permissions))
return false;

const permissionNumber = permissions[resource]!;
if (permissionNumber === PERMISSION_MAPPING.admin && action !== 'admin') return true;

return false;
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import Auth from '@/lib/AuthCanWrapper';
'use client';

import { toCaslResource } from '@/lib/ability/caslAbility';
import { useGetAsset, usePutAsset } from '@/lib/fetch-data';
import { useAuthStore } from '@/lib/iam';
import { Alert, App, Button, DatePicker, Form, Input, Spin } from 'antd';
import { FC } from 'react';
import { FC, useEffect, useState } from 'react';
import dayjs from 'dayjs';
import germanLocale from 'antd/es/date-picker/locale/de_DE';
import { useAbilityStore } from '@/lib/abilityStore';

const RoleGeneralData: FC<{ roleId: string }> = ({ roleId }) => {
const { message } = App.useApp();
const ability = useAuthStore((store) => store.ability);
const ability = useAbilityStore((store) => store.ability);
const [form] = Form.useForm();

const { data, isLoading, error } = useGetAsset('/roles/{id}', {
Expand All @@ -20,6 +21,20 @@ const RoleGeneralData: FC<{ roleId: string }> = ({ roleId }) => {
onError: () => message.open({ type: 'error', content: 'Something went wrong' }),
});

const [submittable, setSubmittable] = useState(false);
const values = Form.useWatch('name', form);

useEffect(() => {
form.validateFields({ validateOnly: true }).then(
() => {
setSubmittable(true);
},
() => {
setSubmittable(false);
},
);
}, [form, values]);

if (isLoading || error || !data) return <Spin />;

const role = toCaslResource('Role', data);
Expand Down Expand Up @@ -50,7 +65,13 @@ const RoleGeneralData: FC<{ roleId: string }> = ({ roleId }) => {
<br />
</>
)}
<Form.Item label="Name" name="name">

<Form.Item
label="Name"
name="name"
rules={[{ required: true, message: 'this field is required' }]}
required
>
<Input placeholder="input placeholder" disabled={!ability.can('update', role, 'name')} />
</Form.Item>

Expand All @@ -72,19 +93,12 @@ const RoleGeneralData: FC<{ roleId: string }> = ({ roleId }) => {
</Form.Item>

<Form.Item>
<Button type="primary" htmlType="submit" loading={putLoading}>
Submit
<Button type="primary" htmlType="submit" loading={putLoading} disabled={!submittable}>
Update Role
</Button>
</Form.Item>
</Form>
);
};

export default Auth(
{
action: ['view', 'manage'],
resource: 'Role',
fallbackRedirect: '/',
},
RoleGeneralData,
);
export default RoleGeneralData;
Loading

0 comments on commit 96ee1ae

Please sign in to comment.