Skip to content

Commit d89d2a5

Browse files
authored
Merge pull request #56 from Wavely-project/routes-v1
cherry-picked the changes out of seeders
2 parents 3cc3ccd + da8e795 commit d89d2a5

28 files changed

+863
-53
lines changed

db/migrations/20240412003023_add_invites_table.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ export async function up(knex: Knex): Promise<void> {
2020
return knex.schema.createTable('invites', (table) => {
2121
table.increments('id').primary();
2222
table.integer('workspaceId').unsigned();
23-
table.integer('inviteeId').unsigned();
2423
table.integer('senderId').unsigned();
24+
table.integer('inviteeId').unsigned();
2525

2626
table.timestamps(true, true, true);
2727
table.timestamp('expiresAt').notNullable();

src/api-docs/openAPIDocumentGenerator.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import { OpenApiGeneratorV3, OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
22

3+
import { channelRegistery } from '@/api/channels/channelRouter';
4+
import { healthCheckRegistry } from '@/api/healthCheck/healthCheckRouter';
5+
import { messageRegistery } from '@/api/messages/messageRouter';
36
import { filesRegistry } from '@/api/files/filesRoutes';
47
// import { channelRegistery } from '@/api/channels/channelRouter';
58
import { healthCheckRegistry } from '@/api/healthCheck/healthCheckRouter';
69
import { notificationsRegistry } from '@/api/notifications/notificationsRoutes';
710
import { reactionsRegistry } from '@/api/reactions/reactionsRouter';
811
import { userRegistry } from '@/api/user/userRouter';
12+
import { workspaceRegistry } from '@/api/workspace/workspaceRouter';
913

10-
// import { workspaceRegistry } from '@/api/workspace/workspaceRouter';
1114
import { authRegistry } from '../api/auth/authRouter';
1215

1316
export function generateOpenAPIDocument() {
1417
const registry = new OpenAPIRegistry([
1518
healthCheckRegistry,
19+
authRegistry,
20+
userRegistry,
21+
workspaceRegistry,
22+
channelRegistery,
23+
messageRegistery,
1624
userRegistry,
1725
authRegistry,
1826
filesRegistry,

src/api/channels/channelController.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Request, Response } from 'express';
2+
3+
import { CreateChannel } from './channelModel';
4+
5+
const ChannelController = {
6+
getChannelById: async (req: Request, res: Response) => {
7+
const id = parseInt(req.params.id);
8+
res.json({ id });
9+
},
10+
createChannel: async (req: Request, res: Response) => {
11+
const { name, description, type, workspaceId } = req.body;
12+
13+
const createChannelPayload: CreateChannel = {
14+
name,
15+
description,
16+
type,
17+
workspaceId,
18+
creatorId: res.locals.user.id,
19+
};
20+
res.json(createChannelPayload);
21+
},
22+
updateChannel: async (req: Request, res: Response) => {
23+
const id = parseInt(req.params.id);
24+
const { name, description, type } = req.body;
25+
res.json({ id, name, description, type });
26+
},
27+
deleteChannel: async (req: Request, res: Response) => {
28+
const id = parseInt(req.params.id);
29+
res.json({ id });
30+
},
31+
getWorkspaceChannels: async (req: Request, res: Response) => {
32+
const workspaceId = parseInt(req.params.id);
33+
const { cursor, limit } = req.query;
34+
console.log(cursor, limit, workspaceId);
35+
res.json({ 1: 1 });
36+
},
37+
getWorkspaceThreads: async (req: Request, res: Response) => {
38+
const workspaceId = parseInt(req.params.id);
39+
const { cursor, limit } = req.query;
40+
console.log(cursor, limit, workspaceId);
41+
res.json({ 1: 1 });
42+
},
43+
};
44+
45+
export default ChannelController;

src/api/channels/channelModel.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ export type CreateChannelDto = Omit<Channel, 'id' | 'createdAt' | 'updatedAt'>;
2424
// Input Validation for 'GET Channel /:id' endpoint
2525
export const GetChannelSchema = z.object({
2626
params: z.object({ id: commonValidations.id }),
27+
query: z.object({
28+
limit: z.string().optional(),
29+
cursor: z.string().optional(),
30+
}),
2731
});
2832
export const CreateChannelSchema = z.object({
2933
body: z.object({
@@ -33,6 +37,19 @@ export const CreateChannelSchema = z.object({
3337
workspaceId: commonValidations.id,
3438
}),
3539
});
40+
export const UpdateChannelSchema = z.object({
41+
body: z.object({
42+
name: z.string(),
43+
description: z.string(),
44+
type: z.enum(['public', 'private', 'direct']),
45+
}),
46+
params: z.object({ id: commonValidations.id }),
47+
});
48+
export const DeleteChannelSchema = z.object({
49+
params: z.object({ id: commonValidations.id }),
50+
});
51+
52+
export const Channels = z.array(ChannelSchema);
3653

3754
export type DeleteChannelData = Omit<
3855
Channel,

src/api/channels/channelRouter.ts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
2+
import express, { Router } from 'express';
3+
4+
import {
5+
ChannelSchema,
6+
CreateChannelSchema,
7+
DeleteChannelSchema,
8+
GetChannelSchema,
9+
UpdateChannelSchema,
10+
} from '@/api/channels/channelModel';
11+
import { createApiResponse } from '@/api-docs/openAPIResponseBuilders';
12+
import { messageResponse } from '@/common/utils/commonResponses';
13+
import { validateRequest } from '@/common/utils/httpHandlers';
14+
15+
import AuthController from '../auth/authController';
16+
import MembersController from '../members/memberController';
17+
import MessageController from '../messages/messageController';
18+
import { Messages } from '../messages/messageModel';
19+
import { Users } from '../user/userModel';
20+
import ChannelController from './channelController';
21+
22+
export const channelRegistery = new OpenAPIRegistry();
23+
24+
const bearerAuth = channelRegistery.registerComponent('securitySchemes', 'bearerAuth', {
25+
type: 'http',
26+
scheme: 'bearer',
27+
bearerFormat: 'JWT',
28+
});
29+
30+
channelRegistery.register('Channel', ChannelSchema);
31+
32+
export const channelRouter: Router = (() => {
33+
const router = express.Router();
34+
35+
channelRegistery.registerPath({
36+
method: 'post',
37+
path: '/channels',
38+
tags: ['Channel'],
39+
security: [{ [bearerAuth.name]: [] }],
40+
request: {
41+
body: {
42+
content: {
43+
'application/json': {
44+
schema: CreateChannelSchema.shape.body,
45+
},
46+
},
47+
},
48+
},
49+
responses: createApiResponse(ChannelSchema, 'Success'),
50+
});
51+
52+
router.post(
53+
'/',
54+
[AuthController.authenticate, validateRequest(CreateChannelSchema)],
55+
ChannelController.createChannel
56+
);
57+
58+
/***************************************************************************** */
59+
channelRegistery.registerPath({
60+
method: 'get',
61+
path: '/channels/{id}',
62+
tags: ['Channel'],
63+
security: [{ [bearerAuth.name]: [] }],
64+
request: { params: GetChannelSchema.shape.params },
65+
responses: createApiResponse(ChannelSchema, 'Success'),
66+
});
67+
68+
router.get(
69+
'/:id',
70+
AuthController.authenticate,
71+
validateRequest(GetChannelSchema),
72+
ChannelController.getChannelById
73+
);
74+
75+
/***************************************************************************** */
76+
channelRegistery.registerPath({
77+
method: 'patch',
78+
path: '/channels/{id}',
79+
tags: ['Channel'],
80+
security: [{ [bearerAuth.name]: [] }],
81+
request: {
82+
params: UpdateChannelSchema.shape.params,
83+
body: {
84+
content: {
85+
'application/json': {
86+
schema: UpdateChannelSchema.shape.body,
87+
},
88+
},
89+
},
90+
},
91+
responses: createApiResponse(ChannelSchema, 'Success'),
92+
});
93+
94+
router.patch(
95+
'/:id',
96+
[AuthController.authenticate, validateRequest(UpdateChannelSchema)],
97+
ChannelController.updateChannel
98+
);
99+
100+
/***************************************************************************** */
101+
channelRegistery.registerPath({
102+
method: 'delete',
103+
path: '/channels/{id}',
104+
tags: ['Channel'],
105+
security: [{ [bearerAuth.name]: [] }],
106+
request: { params: GetChannelSchema.shape.params },
107+
responses: createApiResponse(messageResponse, 'Success'),
108+
});
109+
110+
router.delete(
111+
'/:id',
112+
[AuthController.authenticate, validateRequest(DeleteChannelSchema)],
113+
ChannelController.deleteChannel
114+
);
115+
116+
/***************************************************************************** */
117+
channelRegistery.registerPath({
118+
method: 'get',
119+
path: '/channels/{id}/users',
120+
tags: ['Channel'],
121+
security: [{ bearerAuth: [] }],
122+
request: { params: GetChannelSchema.shape.params },
123+
responses: createApiResponse(Users, 'Success'),
124+
});
125+
126+
router.get(
127+
'/:id/users',
128+
[AuthController.authenticate, validateRequest(GetChannelSchema)],
129+
MembersController.getChannelUsers
130+
);
131+
132+
/***************************************************************************** */
133+
channelRegistery.registerPath({
134+
method: 'get',
135+
path: '/channels/{id}/messages',
136+
tags: ['Channel'],
137+
security: [{ bearerAuth: [] }],
138+
request: { params: GetChannelSchema.shape.params, query: GetChannelSchema.shape.query },
139+
responses: createApiResponse(Messages, 'Success'),
140+
});
141+
142+
router.get(
143+
'/:id/messages',
144+
[AuthController.authenticate, validateRequest(GetChannelSchema)],
145+
MessageController.getChannelMessages
146+
);
147+
148+
return router;
149+
})();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Request, Response } from 'express';
2+
3+
import { CreateCoworker } from './coworkersModel';
4+
5+
const CoworkersController = {
6+
getWorkspaceUsers: async (req: Request, res: Response) => {
7+
const workspaceId = parseInt(req.params.id);
8+
res.json({ workspaceId });
9+
},
10+
getCoworkerById: async (req: Request, res: Response) => {
11+
const id = parseInt(req.params.id);
12+
res.json({ id });
13+
},
14+
createCoworker: async (req: Request, res: Response) => {
15+
const userId = parseInt(req.params.userId);
16+
const workspaceId = parseInt(req.params.workspaceId);
17+
18+
const createCoworkerPayload: CreateCoworker = {
19+
userId,
20+
workspaceId,
21+
};
22+
res.json(createCoworkerPayload);
23+
},
24+
updateCoworker: async (req: Request, res: Response) => {
25+
const userId = parseInt(req.params.userId);
26+
const workspaceId = parseInt(req.params.workspaceId);
27+
res.json({ userId, workspaceId });
28+
},
29+
deleteCoworker: async (req: Request, res: Response) => {
30+
const id = parseInt(req.params.id);
31+
res.json({ id });
32+
},
33+
};
34+
35+
export default CoworkersController;

src/api/coworkers/coworkersModel.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,19 @@ export const BaseCoworkerSchema = z.object({
1010
export const CoworkerSchema = BaseCoworkerSchema.extend({
1111
createdAt: z.string(),
1212
});
13+
export const CreateCoworkerSchema = z.object({
14+
params: z.object({ userId: z.number(), workspaceId: z.number() }),
15+
});
16+
17+
export const GetCoworkersSchema = z.object({
18+
params: z.object({ workspaceId: z.number() }),
19+
});
1320

21+
export const deleteCoworkerSchema = z.object({
22+
params: z.object({ userId: z.number(), workspaceId: z.number() }),
23+
});
1424
export type Coworker = z.infer<typeof CoworkerSchema>;
1525
export type CreateCoworker = z.infer<typeof BaseCoworkerSchema>;
1626
export type CreateCoworkerDto = Omit<Coworker, 'createdAt'>;
1727

18-
// Input Validation for 'GET Coworker/:id' endpoint
19-
export const CreateCoworkerSchema = z.object({
20-
body: z.object({
21-
userId: z.number(),
22-
channelId: z.number(),
23-
}),
24-
});
25-
2628
export type CoworkerData = Coworker & { userData: User };

src/api/invites/invitesController.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import db from 'db/db';
2+
import { Request, Response } from 'express';
3+
4+
import { CreateInvite } from './invitesModel';
5+
import invitesRepository from './invitesRepository';
6+
7+
const InvitesController = {
8+
createInvite: async (req: Request, res: Response) => {
9+
const { inviteeEmail, workspaceId } = req.body;
10+
11+
const createInvitePayload: CreateInvite = {
12+
inviteeEmail,
13+
workspaceId,
14+
senderId: res.locals.user.id,
15+
status: 'pending',
16+
expiresAt: new Date(Date.now() + 200 * 60 * 60 * 1000),
17+
};
18+
19+
const invite = await invitesRepository.createInvite(db, createInvitePayload);
20+
res.json(invite);
21+
},
22+
getInviteById: async (req: Request, res: Response) => {
23+
const id = req.params.id;
24+
const invite = await invitesRepository.getInviteById(db, id);
25+
res.json(invite);
26+
},
27+
28+
getWorkspaceInvites: async (req: Request, res: Response) => {
29+
const workspaceId = req.params.id;
30+
const invites = await invitesRepository.getInviteByWorkspaceId(db, workspaceId);
31+
res.json(invites);
32+
},
33+
acceptInvite: async (req: Request, res: Response) => {
34+
const id = req.params.id;
35+
await invitesRepository.acceptInvite(db, id);
36+
res.sendStatus(200);
37+
},
38+
cancelInvite: async (req: Request, res: Response) => {
39+
const id = req.params.id;
40+
await invitesRepository.cancelInvite(db, id);
41+
res.sendStatus(200);
42+
},
43+
};
44+
45+
export default InvitesController;

0 commit comments

Comments
 (0)