Skip to content

Commit

Permalink
Add reminder routes
Browse files Browse the repository at this point in the history
  • Loading branch information
SupertigerDev committed Dec 5, 2024
1 parent 42ebafe commit 6507f1c
Show file tree
Hide file tree
Showing 13 changed files with 378 additions and 121 deletions.
20 changes: 20 additions & 0 deletions prisma/migrations/20241205125506_create_reminder/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- CreateTable
CREATE TABLE "Reminder" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"remindAt" TIMESTAMP(3) NOT NULL,
"createdById" TEXT NOT NULL,
"postId" TEXT,
"messageId" TEXT,

CONSTRAINT "Reminder_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "Reminder" ADD CONSTRAINT "Reminder_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Reminder" ADD CONSTRAINT "Reminder_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Reminder" ADD CONSTRAINT "Reminder_messageId_fkey" FOREIGN KEY ("messageId") REFERENCES "Message"("id") ON DELETE SET NULL ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "Reminder" ADD COLUMN "channelId" TEXT;

-- AddForeignKey
ALTER TABLE "Reminder" ADD CONSTRAINT "Reminder_channelId_fkey" FOREIGN KEY ("channelId") REFERENCES "Channel"("id") ON DELETE SET NULL ON UPDATE CASCADE;
28 changes: 28 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ model User {
openedTickets Ticket[]
reminders Reminder[]
application Application? // Bot users will have this
usersSuspended Suspension[] @relation(name: "suspended_by") // Only admins
Expand Down Expand Up @@ -517,6 +519,8 @@ model Channel {
notificationSettings UserNotificationSettings[]
permissions ServerChannelPermissions[]
reminders Reminder[]
}

model ServerChannelPermissions {
Expand Down Expand Up @@ -601,6 +605,7 @@ model Message {
silent Boolean?
reminders Reminder[]
Expand Down Expand Up @@ -791,6 +796,9 @@ model Post {
poll PostPoll?
reminders Reminder[]
@@index([createdById, createdAt])
}
Expand Down Expand Up @@ -914,4 +922,24 @@ model AuditLog {
@@index([actionById, createdAt])
@@index([serverId, createdAt])
}


model Reminder {
id String @id
createdAt DateTime @default(now())
remindAt DateTime
createdById String
createdBy User @relation(fields: [createdById], references: [id], onDelete: Cascade)
postId String?
post Post? @relation(fields: [postId], references: [id], onDelete: SetNull)
messageId String?
message Message? @relation(fields: [messageId], references: [id], onDelete: SetNull)
channelId String?
channel Channel? @relation(fields: [channelId], references: [id], onDelete: SetNull)
}
2 changes: 2 additions & 0 deletions src/common/ClientEventNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export const USER_CONNECTION_ADDED = 'user:connection_added';
export const USER_CONNECTION_REMOVED = 'user:connection_removed';

export const USER_NOTIFICATION_SETTINGS_UPDATE = 'user:notification_settings_update';
export const USER_REMINDER_ADD = 'user:reminder_add';
export const USER_REMINDER_REMOVE = 'user:reminder_remove';

export const USER_PRESENCE_UPDATE = 'user:presence_update';
export const USER_BLOCKED = 'user:blocked';
Expand Down
12 changes: 12 additions & 0 deletions src/emits/Reminder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { USER_REMINDER_ADD, USER_REMINDER_REMOVE } from '../common/ClientEventNames';
import { getIO } from '../socket/socket';
import { PartialReminder } from '../services/Reminder';

export const emitReminderAdd = (userId: string, reminder: PartialReminder) => {
const io = getIO();
io.in(userId).emit(USER_REMINDER_ADD, reminder);
};
export const emitReminderRemove = (userId: string, reminderId: string) => {
const io = getIO();
io.in(userId).emit(USER_REMINDER_REMOVE, { id: reminderId });
};
10 changes: 10 additions & 0 deletions src/routes/reminders/Router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Router } from 'express';
import { remindersAddRoute } from './remindersAddRoute';
import { remindersDeleteRoute } from './remindersDeleteRoute';

const RemindersRouter = Router();

remindersAddRoute(RemindersRouter);
remindersDeleteRoute(RemindersRouter);

export { RemindersRouter };
52 changes: 52 additions & 0 deletions src/routes/reminders/remindersAddRoute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Request, Response, Router } from 'express';

import { authenticate } from '../../middleware/authenticate';
import { rateLimit } from '../../middleware/rateLimit';
import { body } from 'express-validator';
import { customExpressValidatorResult } from '../../common/errorHandler';
import { addReminder } from '../../services/Reminder';

export function remindersAddRoute(Router: Router) {
Router.post(
'/reminders',
authenticate(),
body('timestamp').not().isEmpty().withMessage('timestamp is required.').isNumeric().isLength({ min: 1, max: 255 }).withMessage('Invalid timestamp.'),

body('postId').optional(true).isString().withMessage('postId must be a string').isLength({ min: 1, max: 255 }).withMessage('postId must be between 1 and 255 characters long'),
body('messageId').optional(true).isString().withMessage('messageId must be a string').isLength({ min: 1, max: 255 }).withMessage('messageId must be between 1 and 255 characters long'),

rateLimit({
name: 'reminders_add',
restrictMS: 60000,
requests: 5,
}),
route
);
}

interface Body {
timestamp: number;
postId?: string;
messageId?: string;
}
async function route(req: Request, res: Response) {
const body = req.body as Body;

const validateError = customExpressValidatorResult(req);

if (validateError) {
return res.status(400).json(validateError);
}

if (!body.postId && !body.messageId) {
return res.status(400).json('postId or messageId is required.');
}

const [reminder, error] = await addReminder({ userId: req.userCache.id, timestamp: body.timestamp, messageId: body.messageId, postId: body.postId });

if (error) {
return res.status(400).json(error);
}

return res.status(200).json(reminder);
}
31 changes: 31 additions & 0 deletions src/routes/reminders/remindersDeleteRoute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Request, Response, Router } from 'express';

import { authenticate } from '../../middleware/authenticate';
import { rateLimit } from '../../middleware/rateLimit';
import { deleteReminder } from '../../services/Reminder';

export function remindersDeleteRoute(Router: Router) {
Router.delete(
'/reminders/:id',
authenticate(),

rateLimit({
name: 'reminders_delete',
restrictMS: 60000,
requests: 20,
}),
route
);
}

async function route(req: Request, res: Response) {
const id = req.params.id as string;

const [reminder, error] = await deleteReminder(id, req.userCache.id);

if (error) {
return res.status(400).json(error);
}

return res.status(200).json(reminder);
}
Loading

0 comments on commit 6507f1c

Please sign in to comment.