diff --git a/README.md b/README.md index 9656c73..778407b 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ pnpm --filter web test - [x] realtime member list update - [x] infinite scroll cursor pagination (messages/groups/members) - [x] tanstack react-query integration +- [x] add members - [ ] alert component - [ ] confirm dialog - [ ] delete group diff --git a/server/global.d.ts b/server/global.d.ts index 8d5c471..cb6c082 100644 --- a/server/global.d.ts +++ b/server/global.d.ts @@ -7,5 +7,9 @@ interface UserPayload { declare namespace Express { export interface Request { user?: UserPayload + group?: { + id: number + role: 'owner' | 'admin' | 'member' + } } } diff --git a/server/src/middlewares.ts b/server/src/middlewares.ts index 3e7dbb9..82a2cdf 100644 --- a/server/src/middlewares.ts +++ b/server/src/middlewares.ts @@ -44,12 +44,21 @@ export const hasGroupPermission = return notAuthorized(res) } - const isAllowed = await checkPermission(groupId, req.user!.id, role) + const { isAllowed, memberRole } = await checkPermission( + groupId, + req.user!.id, + role, + ) if (!isAllowed) { return notAuthorized(res) } + req.group = { + id: groupId, + role: memberRole!, + } + next() } catch (error) { notAuthorized(res) diff --git a/server/src/modules/groups/groups.routes.ts b/server/src/modules/groups/groups.routes.ts index b2cb57a..69bdbf7 100644 --- a/server/src/modules/groups/groups.routes.ts +++ b/server/src/modules/groups/groups.routes.ts @@ -1,6 +1,9 @@ import { hasGroupPermission } from '@/middlewares' import { Router } from 'express' -import { getGroupMembers } from '../members/members.controller' +import { + getCurrentMember, + getGroupMembers, +} from '../members/members.controller' import { createMessage, listMessages } from '../messages/messages.controller' import { addGroupMembers, @@ -21,6 +24,11 @@ router.delete('/:groupId', hasGroupPermission('owner'), deleteGroup) router.post('/:groupId/members', hasGroupPermission('admin'), addGroupMembers) router.get('/:groupId/members', hasGroupPermission('member'), getGroupMembers) +router.get( + '/:groupId/members/current', + hasGroupPermission('member'), + getCurrentMember, +) router.get( '/:groupId/non-members', hasGroupPermission('admin'), diff --git a/server/src/modules/members/members.controller.ts b/server/src/modules/members/members.controller.ts index 2413c81..4d700ff 100644 --- a/server/src/modules/members/members.controller.ts +++ b/server/src/modules/members/members.controller.ts @@ -79,3 +79,11 @@ export const getGroupMembers: RequestHandler = async (req, res, next) => { next(error) } } + +export const getCurrentMember: RequestHandler = (req, res, next) => { + try { + return res.json(req.group) + } catch (error) { + next(error) + } +} diff --git a/server/src/modules/members/members.service.ts b/server/src/modules/members/members.service.ts index 601d16a..2bc0bd7 100644 --- a/server/src/modules/members/members.service.ts +++ b/server/src/modules/members/members.service.ts @@ -25,14 +25,17 @@ export const checkPermission = async ( .limit(1) if (!member) { - return false + return { isAllowed: false } } await setMemberRolesForAGroup(groupId, { [userId]: member.role }) memberRole = member.role } - return memberRoles.indexOf(memberRole) >= memberRoles.indexOf(role) + return { + isAllowed: memberRoles.indexOf(memberRole) >= memberRoles.indexOf(role), + memberRole, + } } export const addMembers = async ( diff --git a/server/src/socket/events.ts b/server/src/socket/events.ts index 9826972..9261d57 100644 --- a/server/src/socket/events.ts +++ b/server/src/socket/events.ts @@ -55,12 +55,12 @@ export const registerSocketEvents = (io: TypedIOServer) => { socket.on('createMessage', async ({ groupId, text }, cb) => { try { - const hasPermission = await checkPermission( + const { isAllowed } = await checkPermission( groupId, socket.data.user!.id, 'member', ) - if (!hasPermission) { + if (!isAllowed) { throw new Error('createMessage: Not authorized') } diff --git a/web/src/layouts/ChatLayout.tsx b/web/src/features/chat/layouts/ChatLayout.tsx similarity index 100% rename from web/src/layouts/ChatLayout.tsx rename to web/src/features/chat/layouts/ChatLayout.tsx diff --git a/web/src/features/member/components/GroupInfo.tsx b/web/src/features/chat/layouts/GroupInfo.tsx similarity index 76% rename from web/src/features/member/components/GroupInfo.tsx rename to web/src/features/chat/layouts/GroupInfo.tsx index ec07c46..2c2c7cf 100644 --- a/web/src/features/member/components/GroupInfo.tsx +++ b/web/src/features/chat/layouts/GroupInfo.tsx @@ -1,11 +1,10 @@ import backArrow from '@/assets/back-svgrepo-com.svg' -import { AddMembers } from './AddMembers' -import { MemberList } from './MemberList' interface MembersListProps { isOpen: boolean onClose: () => void groupId: number + children: React.ReactNode } export const GroupInfo = (props: MembersListProps) => { @@ -27,13 +26,7 @@ export const GroupInfo = (props: MembersListProps) => {