diff --git a/apps/api/src/services/orgs/invites.py b/apps/api/src/services/orgs/invites.py index 50f83488..c8cb5f69 100644 --- a/apps/api/src/services/orgs/invites.py +++ b/apps/api/src/services/orgs/invites.py @@ -215,11 +215,7 @@ async def get_invite_codes( # Get invite codes invite_codes = r.keys(f"org_invite_code_*:org:{org.org_uuid}:code:*") - if not invite_codes: - raise HTTPException( - status_code=404, - detail="Invite codes not found", - ) + invite_codes_list = [] diff --git a/apps/api/src/services/users/usergroups.py b/apps/api/src/services/users/usergroups.py index f5508d0f..cc497762 100644 --- a/apps/api/src/services/users/usergroups.py +++ b/apps/api/src/services/users/usergroups.py @@ -99,11 +99,7 @@ async def read_usergroups_by_org_id( statement = select(UserGroup).where(UserGroup.org_id == org_id) usergroups = db_session.exec(statement).all() - if not usergroups: - raise HTTPException( - status_code=404, - detail="UserGroups not found", - ) + # RBAC check await rbac_check( diff --git a/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx index dc1155cd..b4cab9d6 100644 --- a/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/courses/course/[courseuuid]/[subpage]/page.tsx @@ -27,7 +27,7 @@ function CourseOverviewPage({ params }: { params: CourseOverviewParams }) {
-
+
{ @@ -62,11 +67,10 @@ function UsersSettingsPage({ params }: { params: SettingsParams }) { } >
@@ -74,17 +78,33 @@ function UsersSettingsPage({ params }: { params: SettingsParams }) {
+ +
+
+ +
UserGroups
+
+
+
@@ -98,11 +118,10 @@ function UsersSettingsPage({ params }: { params: SettingsParams }) { } >
@@ -122,6 +141,7 @@ function UsersSettingsPage({ params }: { params: SettingsParams }) { {params.subpage == 'users' ? : ''} {params.subpage == 'signups' ? : ''} {params.subpage == 'add' ? : ''} + {params.subpage == 'usergroups' ? : ''}
) diff --git a/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx b/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx index 74de3d5d..fb274c41 100644 --- a/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx +++ b/apps/web/components/Dashboard/Course/EditCourseAccess/EditCourseAccess.tsx @@ -5,7 +5,7 @@ import Modal from '@components/StyledElements/Modal/Modal' import { getAPIUrl } from '@services/config/config' import { unLinkResourcesToUserGroup } from '@services/usergroups/usergroups' import { swrFetcher } from '@services/utils/ts/requests' -import { Globe, Users, UsersRound, X } from 'lucide-react' +import { Globe, SquareUserRound, Users, UsersRound, X } from 'lucide-react' import React from 'react' import toast from 'react-hot-toast' import useSWR, { mutate } from 'swr' @@ -198,13 +198,14 @@ function UserGroupsSection({ usergroups }: { usergroups: any[] }) { } /> -
+
+ ) } diff --git a/apps/web/components/Dashboard/Users/OrgAccess/OrgAccess.tsx b/apps/web/components/Dashboard/Users/OrgAccess/OrgAccess.tsx index a4de5467..1155bea4 100644 --- a/apps/web/components/Dashboard/Users/OrgAccess/OrgAccess.tsx +++ b/apps/web/components/Dashboard/Users/OrgAccess/OrgAccess.tsx @@ -74,7 +74,6 @@ function OrgAccess() { return ( <> - {!isLoading ? ( <>
diff --git a/apps/web/components/Dashboard/Users/OrgUserGroups/OrgUserGroups.tsx b/apps/web/components/Dashboard/Users/OrgUserGroups/OrgUserGroups.tsx new file mode 100644 index 00000000..fa84eca3 --- /dev/null +++ b/apps/web/components/Dashboard/Users/OrgUserGroups/OrgUserGroups.tsx @@ -0,0 +1,154 @@ +'use client' +import { useOrg } from '@components/Contexts/OrgContext' +import AddUserGroup from '@components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup' +import ManageUsers from '@components/Objects/Modals/Dash/OrgUserGroups/ManageUsers' +import ConfirmationModal from '@components/StyledElements/ConfirmationModal/ConfirmationModal' +import Modal from '@components/StyledElements/Modal/Modal' +import { getAPIUrl } from '@services/config/config' +import { deleteUserGroup } from '@services/usergroups/usergroups' +import { swrFetcher } from '@services/utils/ts/requests' +import { SquareUserRound, Users, X } from 'lucide-react' +import React from 'react' +import toast from 'react-hot-toast' +import useSWR, { mutate } from 'swr' + +function OrgUserGroups() { + const org = useOrg() as any + const [userGroupManagementModal, setUserGroupManagementModal] = React.useState(false) + const [createUserGroupModal, setCreateUserGroupModal] = React.useState(false) + const [selectedUserGroup, setSelectedUserGroup] = React.useState(null) as any + + const { data: usergroups } = useSWR( + org ? `${getAPIUrl()}usergroups/org/${org.id}` : null, + swrFetcher + ) + + const deleteUserGroupUI = async (usergroup_id: any) => { + const res = await deleteUserGroup(usergroup_id) + if (res.status == 200) { + mutate(`${getAPIUrl()}usergroups/org/${org.id}`) + } + else { + toast.error('Error ' + res.status + ': ' + res.data.detail) + } + + } + + const handleUserGroupManagementModal = (usergroup_id: any) => { + setSelectedUserGroup(usergroup_id) + setUserGroupManagementModal(!userGroupManagementModal) + } + + return ( + <> +
+
+
+

Manage UserGroups & Users

+

+ {' '} + UserGroups are a way to group users together to manage their access to the resources (Courses) in your organization.{' '} +

+
+ + + + + + + + + + <> + + {usergroups?.map((usergroup: any) => ( + + + + + + + ))} + + +
UserGroupDescriptionManage UsersActions
{usergroup.name}{usergroup.description} + + handleUserGroupManagementModal(usergroup.id) + } + minHeight="no-min" + dialogContent={ + + } + dialogTitle="Manage UserGroup Users" + dialogDescription={ + 'Manage the users in this UserGroup' + } + dialogTrigger={ + + } + /> + + + + + Delete + + } + functionToExecute={() => { + deleteUserGroupUI(usergroup.id) + }} + status="warning" + > +
+
+ + setCreateUserGroupModal(!createUserGroupModal) + } + minHeight="no-min" + dialogContent={ + + } + dialogTitle="Create a UserGroup" + dialogDescription={ + 'Create a new UserGroup to manage users' + } + dialogTrigger={ + + } + /> +
+ +
+ + + + + ) +} + +export default OrgUserGroups \ No newline at end of file diff --git a/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx b/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx new file mode 100644 index 00000000..e7e4f28b --- /dev/null +++ b/apps/web/components/Objects/Modals/Dash/OrgUserGroups/AddUserGroup.tsx @@ -0,0 +1,99 @@ +'use client' +import FormLayout, { + ButtonBlack, + Flex, + FormField, + FormLabel, + FormMessage, + Input, +} from '@components/StyledElements/Form/Form' +import * as Form from '@radix-ui/react-form' +import { useOrg } from '@components/Contexts/OrgContext' +import React from 'react' +import { BarLoader } from 'react-spinners' +import { createUserGroup } from '@services/usergroups/usergroups' +import { mutate } from 'swr' +import { getAPIUrl } from '@services/config/config' + +type AddUserGroupProps = { + setCreateUserGroupModal: any +} + +function AddUserGroup(props: AddUserGroupProps) { + const org = useOrg() as any + const [userGroupName, setUserGroupName] = React.useState('') + const [userGroupDescription, setUserGroupDescription] = React.useState('') + const [isSubmitting, setIsSubmitting] = React.useState(false) + + const handleNameChange = (event: React.ChangeEvent) => { + setUserGroupName(event.target.value) + } + + const handleDescriptionChange = (event: React.ChangeEvent) => { + setUserGroupDescription(event.target.value) + } + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault() + setIsSubmitting(true) + + const obj = { + name: userGroupName, + description: userGroupDescription, + org_id: org.id + } + const res = await createUserGroup(obj) + if (res.status == 200) { + setIsSubmitting(false) + mutate(`${getAPIUrl()}usergroups/org/${org.id}`) + props.setCreateUserGroupModal(false) + + } else { + setIsSubmitting(false) + } + } + + return ( + + + + Name + + Please provide a ug name + + + + + + + + + Description + + Please provide a ug description + + + + + + + + + + {isSubmitting ? ( + + ) : ( + 'Create UserGroup' + )} + + + + + ) +} + +export default AddUserGroup \ No newline at end of file diff --git a/apps/web/components/Objects/Modals/Dash/OrgUserGroups/ManageUsers.tsx b/apps/web/components/Objects/Modals/Dash/OrgUserGroups/ManageUsers.tsx new file mode 100644 index 00000000..150ce4b6 --- /dev/null +++ b/apps/web/components/Objects/Modals/Dash/OrgUserGroups/ManageUsers.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +function ManageUsers() { + return ( +
ManageUsers
+ ) +} + +export default ManageUsers \ No newline at end of file diff --git a/apps/web/services/usergroups/usergroups.ts b/apps/web/services/usergroups/usergroups.ts index c1387c76..26f4c0f7 100644 --- a/apps/web/services/usergroups/usergroups.ts +++ b/apps/web/services/usergroups/usergroups.ts @@ -10,6 +10,24 @@ export async function getUserGroups(org_id: any) { return res } +export async function createUserGroup(body: any) { + const result: any = await fetch( + `${getAPIUrl()}usergroups`, + RequestBody('POST', body, null) + ) + const res = await getResponseMetadata(result) + return res +} + +export async function deleteUserGroup(usergroup_id: number) { + const result: any = await fetch( + `${getAPIUrl()}usergroups/${usergroup_id}`, + RequestBody('DELETE', null, null) + ) + const res = await getResponseMetadata(result) + return res +} + export async function linkResourcesToUserGroup( usergroup_id: any, resource_uuids: any