Skip to content

Commit

Permalink
Updated schema and initial notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
jeessh committed Nov 22, 2024
1 parent b005021 commit d49c104
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 64 deletions.
26 changes: 20 additions & 6 deletions backend/graphql/resolvers/notificationResolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import NotificationService from "../../services/implementations/notificationServ
import INotificationService, {
NotificationDTO,
NotificationReceivedDTO,
UpdateNotificationDTO,
} from "../../services/interfaces/notificationService";
import IResidentService from "../../services/interfaces/residentService";
import ResidentService from "../../services/implementations/residentService";
Expand All @@ -13,11 +14,11 @@ const notificationService: INotificationService = new NotificationService(

const notificationResolvers = {
Query: {
getNotificationsByUserId: async (
getNotificationsByRoomIds: async (
_parent: undefined,
{ userId }: { userId: string },
{ roomIds }: { roomIds: string[] },
): Promise<NotificationReceivedDTO[]> => {
return notificationService.getNotificationsByUserId(Number(userId));
return notificationService.getNotificationsByRoomIds(roomIds.map(Number));
},
getNotificationById: async (
_parent: undefined,
Expand All @@ -33,15 +34,15 @@ const notificationResolvers = {
authorId,
title,
message,
recipientIds,
roomIds,
}: {
authorId: number;
title: string;
message: string;
recipientIds: number[];
roomIds: number[];
},
): Promise<NotificationDTO> => {
const ids = recipientIds.map((id) => Number(id));
const ids = roomIds.map((id) => Number(id));
const newNotification = await notificationService.sendNotification(
Number(authorId),
title,
Expand All @@ -68,6 +69,19 @@ const notificationResolvers = {
);
return updatedNotification;
},
updateNotification: async (
_parent: undefined,
{
notificationId,
notification,
}: { notificationId: number; notification: UpdateNotificationDTO },
): Promise<NotificationDTO> => {
const updatedNotification = await notificationService.updateNotificationById(
Number(notificationId),
notification,
);
return updatedNotification;
},
sendAnnouncement: async (
_parent: undefined,
{
Expand Down
15 changes: 13 additions & 2 deletions backend/graphql/types/notificationType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@ const notificationType = gql`
seen: Boolean!
}
input UpdateNotificationDTO {
authorId: ID
title: String
message: String
createdAt: DateTime
}
extend type Query {
getNotificationsByUserId(userId: ID!): [NotificationReceivedDTO!]
getNotificationsByRoomIds(roomIds: [Int!]): [NotificationReceivedDTO!]
getNotificationById(id: ID!): NotificationReceivedDTO!
}
Expand All @@ -27,10 +34,14 @@ const notificationType = gql`
authorId: ID!
title: String!
message: String!
recipientIds: [ID!]
roomIds: [Int!]
): NotificationDTO!
deleteUserNotification(notificationId: ID!): NotificationDTO!
updateSeenNotification(notificationId: ID!): NotificationReceivedDTO!
updateNotification(
notificationId: ID!
notification: UpdateNotificationDTO!
): NotificationDTO!
sendAnnouncement(
title: String
message: String
Expand Down
82 changes: 44 additions & 38 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -15,46 +15,45 @@ enum UserType {
}

model User {
id Int @id @default(autoincrement())
type UserType
staff Staff?
resident Resident?
authId String @unique @map("auth_id")
displayName String? @map("display_name")
profilePictureURL String? @map("profile_picture_url")
isActive Boolean @default(true) @map("is_active")
notificationsSent Notification[]
notificationsReceived NotificationReceived[]
id Int @id @default(autoincrement())
type UserType
staff Staff?
resident Resident?
authId String @unique @map("auth_id")
displayName String? @map("display_name")
profilePictureURL String? @map("profile_picture_url")
isActive Boolean @default(true) @map("is_active")
@@map("users")
}

model Staff {
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
userId Int @id @map("user_id")
email String @unique @map("email")
phoneNumber String? @unique @map("phone_number")
firstName String @map("first_name")
lastName String @map("last_name")
isAdmin Boolean @default(false) @map("is_admin")
tasksAssigned TaskAssigned[]
warningsAssigned Warning[]
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
userId Int @id @map("user_id")
email String @unique @map("email")
phoneNumber String? @unique @map("phone_number")
firstName String @map("first_name")
lastName String @map("last_name")
isAdmin Boolean @default(false) @map("is_admin")
tasksAssigned TaskAssigned[]
warningsAssigned Warning[]
NotificationsSent Notification[]
@@map("staff")
}

model Resident {
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
userId Int @id @map("user_id")
residentId Int @unique @map("resident_id") // Differs from user id, this id is assigned by the staff
// birthDate DateTime @map("birth_date") @db.Date
roomNumber Int @map("room_number")
credits Float @default(0)
dateJoined DateTime @default(now()) @map("date_joined") @db.Date
dateLeft DateTime? @map("date_left") @db.Date
// notes String?
tasks TaskAssigned[]
warnings Warning[]
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
userId Int @id @map("user_id")
residentId Int @unique @map("resident_id") // Differs from user id, this id is assigned by the staff
roomNumber Int @map("room_number")
credits Float @default(0)
dateJoined DateTime @default(now()) @map("date_joined") @db.Date
dateLeft DateTime? @map("date_left") @db.Date
tasks TaskAssigned[]
warnings Warning[]
notificationGroup NotificationGroup[]
notificationRecieved NotificationReceived[]
@@map("residents")
}
Expand Down Expand Up @@ -147,14 +146,21 @@ model Warning {
@@map("warnings")
}

model NotificationGroup {
id Int @id @default(autoincrement())
recipients Resident[]
notifications Notification[]
}

model Notification {
id Int @id @default(autoincrement())
author User? @relation(fields: [authorId], references: [id], onDelete: SetNull, onUpdate: Cascade)
authorId Int? @map("author_id")
title String
message String
createdAt DateTime @default(now()) @map("created_at") @db.Date
recipients NotificationReceived[]
id Int @id @default(autoincrement())
message String
createdAt DateTime @default(now()) @map("created_at") @db.Date
author Staff? @relation(fields: [authorId], references: [userId], onDelete: SetNull, onUpdate: Cascade)
authorId Int? @map("author_id")
group NotificationGroup @relation(fields: [groupId], references: [id])
groupId Int @map("group_id")
notificationReceived NotificationReceived[]
@@map("notifications")
}
Expand All @@ -163,7 +169,7 @@ model NotificationReceived {
id Int @id @default(autoincrement())
notification Notification @relation(fields: [notificationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
notificationId Int @map("notification_id")
recipient User @relation(fields: [recipientId], references: [id], onDelete: Cascade, onUpdate: Cascade)
recipient Resident @relation(fields: [recipientId], references: [userId], onDelete: Cascade, onUpdate: Cascade)
recipientId Int @map("recipient_id")
seen Boolean @default(false)
Expand Down
63 changes: 49 additions & 14 deletions backend/services/implementations/notificationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import prisma from "../../prisma";
import INotificationService, {
NotificationDTO,
NotificationReceivedDTO,
UpdateNotificationDTO,
} from "../interfaces/notificationService";
import IResidentService from "../interfaces/residentService";
import logger from "../../utilities/logger";
Expand All @@ -16,20 +17,20 @@ class NotificationService implements INotificationService {
this.residentService = residentService;
}

async getNotificationsByUserId(
id: number,
async getNotificationsByRoomIds(
roomIds: number[],
): Promise<NotificationReceivedDTO[]> {
try {
const user = await prisma.user.findUnique({
where: {
id,
},
include: {
notificationsReceived: true,
},
const residents = await prisma.resident.findMany({
where: { roomNumber: { in: roomIds } },
});
if (!user) throw new Error(`No User found.`);
return user.notificationsReceived;
const residentIds = residents.map((resident) => resident.userId);

const notificationReceived = await prisma.notificationReceived.findMany({
where: { recipientId: { in: residentIds } },
});
if (!notificationReceived) throw new Error(`No User found.`);
return notificationReceived;
} catch (error) {
Logger.error(
`Failed to get Notification. Reason = ${getErrorMessage(error)}`,
Expand Down Expand Up @@ -60,9 +61,14 @@ class NotificationService implements INotificationService {
authorId: number,
title: string,
message: string,
recipientIds: number[],
roomIds: number[],
): Promise<NotificationDTO> {
try {
const residents = await prisma.resident.findMany({
where: { roomNumber: { in: roomIds } },
});
const residentIds = residents.map((resident) => resident.userId);

const newNotification = await prisma.notification.create({
data: {
title,
Expand All @@ -71,10 +77,10 @@ class NotificationService implements INotificationService {
connect: { id: authorId },
},
recipients: {
create: recipientIds.map((recipient) => ({
create: residentIds.map((resident) => ({
recipient: {
connect: {
id: recipient,
id: resident,
},
},
})),
Expand Down Expand Up @@ -148,6 +154,35 @@ class NotificationService implements INotificationService {
}
}

async updateNotificationById(
notificationId: number,
notification: UpdateNotificationDTO,
): Promise<NotificationDTO> {
try {
const updatedNotification = await prisma.notification.update({
where: {
id: notificationId,
},
data: {
...notification,
},
include: {
recipients: true,
},
});

if (!updatedNotification)
throw new Error(`notification id ${notificationId} not found`);

return updatedNotification;
} catch (error) {
Logger.error(
`Failed to set seen flag. Reason = ${getErrorMessage(error)}`,
);
throw error;
}
}

async sendAnnouncement(
title: string,
message: string,
Expand Down
27 changes: 23 additions & 4 deletions backend/services/interfaces/notificationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ export interface NotificationDTO {
recipients: NotificationReceivedDTO[];
}

export interface UpdateNotificationDTO {
authorId?: number;
title?: string;
message?: string;
createdAt?: Date;
}

export interface NotificationReceivedDTO {
id: number;
notificationId: number;
Expand All @@ -21,7 +28,9 @@ interface INotificationService {
* @returns a NotificationDTO[] associated with that users notifications
* @throws Error if retrieval fails
*/
getNotificationsByUserId(id: number): Promise<NotificationReceivedDTO[]>;
getNotificationsByRoomIds(
roomIds: number[],
): Promise<NotificationReceivedDTO[]>;

/**
* Get a notification by a defined id
Expand All @@ -36,15 +45,15 @@ interface INotificationService {
* @param authorId user id of author of notification
* @param title title of notification
* @param message message of notification
* @param recipientIds user ids of recipients of notification
* @param roomIds room ids of recipients of notification
* @returns a NotificationDTO associated with the posted notifications
* @throws Error if creation fails
*/
sendNotification(
authorId: number,
title: string,
message: string,
recipientIds: number[],
roomIds: number[],
): Promise<NotificationDTO>;

/**
Expand All @@ -58,7 +67,6 @@ interface INotificationService {

/**
* Update a user notification to be seen
* @param userId user id
* @param notificationId notification id
* @returns a NotificationDTO associated with the now seen Notification
* @throws Error if retrieval fails
Expand All @@ -67,6 +75,17 @@ interface INotificationService {
notificationId: number,
): Promise<NotificationReceivedDTO>;

/**
* Update a user notification to be seen
* @param notificationId notification id
* @returns a NotificationDTO associated with the updated Notification
* @throws Error if retrieval fails
*/
updateNotificationById(
notificationId: number,
notification: UpdateNotificationDTO,
): Promise<NotificationDTO>;

/**
* Post an announcement notification to all active residents
* @param title title of announcement
Expand Down

0 comments on commit d49c104

Please sign in to comment.