-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Built out shift signup endpoints #90
Changes from all commits
7a0eca1
b1ef918
ddbe06b
2312ea5
718cf5f
3377254
42ff948
5b3e3d9
ab2e68c
027949f
fc9f0cc
486aeae
a720ed4
cf4d19d
c5a9874
9f0e3bf
d57e636
6095a1a
d0da7d9
8d3412f
d17593e
50429f1
7fcbc99
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import ShiftSignupService from "../../services/implementations/shiftSignupService"; | ||
import IShiftSignupService from "../../services/interfaces/shiftSignupService"; | ||
import { | ||
CreateShiftSignupDTO, | ||
ShiftSignupResponseDTO, | ||
UpdateShiftSignupRequestDTO, | ||
} from "../../types"; | ||
|
||
const shiftSignupService: IShiftSignupService = new ShiftSignupService(); | ||
|
||
const shiftSignupResolvers = { | ||
Query: { | ||
getShiftSignupsForUser: async ( | ||
_parent: undefined, | ||
{ userId }: { userId: string }, | ||
): Promise<ShiftSignupResponseDTO[]> => { | ||
return shiftSignupService.getShiftSignupsForUser(userId); | ||
}, | ||
}, | ||
Mutation: { | ||
createShiftSignups: async ( | ||
_parent: undefined, | ||
{ shifts }: { shifts: CreateShiftSignupDTO[] }, | ||
): Promise<ShiftSignupResponseDTO[]> => { | ||
return shiftSignupService.createShiftSignups(shifts); | ||
}, | ||
|
||
updateShiftSignup: async ( | ||
_parent: undefined, | ||
{ | ||
shiftId, | ||
userId, | ||
update, | ||
}: { | ||
shiftId: string; | ||
userId: string; | ||
update: UpdateShiftSignupRequestDTO; | ||
}, | ||
): Promise<ShiftSignupResponseDTO> => { | ||
return shiftSignupService.updateShiftSignup(shiftId, userId, update); | ||
}, | ||
}, | ||
}; | ||
|
||
export default shiftSignupResolvers; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { gql } from "apollo-server-express"; | ||
|
||
const shiftSignupType = gql` | ||
enum SignupStatus { | ||
PENDING | ||
CONFIRMED | ||
CANCELED | ||
} | ||
|
||
input CreateShiftSignupRequestDTO { | ||
shiftId: ID! | ||
userId: ID! | ||
numVolunteers: Int! | ||
note: String! | ||
} | ||
|
||
input UpdateShiftSignupRequestDTO { | ||
numVolunteers: Int! | ||
note: String! | ||
status: SignupStatus! | ||
} | ||
|
||
type ShiftSignupResponseDTO { | ||
shiftId: ID! | ||
userId: ID! | ||
numVolunteers: Int! | ||
note: String! | ||
status: SignupStatus! | ||
} | ||
|
||
extend type Query { | ||
getShiftSignupsForUser(userId: ID!): [ShiftSignupResponseDTO!]! | ||
} | ||
|
||
extend type Mutation { | ||
createShiftSignups( | ||
shifts: [CreateShiftSignupRequestDTO!]! | ||
): [ShiftSignupResponseDTO!]! | ||
updateShiftSignup( | ||
shiftId: ID! | ||
userId: ID! | ||
update: UpdateShiftSignupRequestDTO! | ||
): ShiftSignupResponseDTO! | ||
} | ||
`; | ||
|
||
export default shiftSignupType; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/* | ||
Warnings: | ||
|
||
- The primary key for the `signups` table will be changed. If it partially fails, the table could be left without primary key constraint. | ||
- You are about to drop the column `id` on the `signups` table. All the data in the column will be lost. | ||
- Added the required column `note` to the `signups` table without a default value. This is not possible if the table is not empty. | ||
|
||
*/ | ||
-- AlterTable | ||
ALTER TABLE "signups" DROP CONSTRAINT "signups_pkey", | ||
DROP COLUMN "id", | ||
ADD COLUMN "note" TEXT NOT NULL, | ||
ADD CONSTRAINT "signups_pkey" PRIMARY KEY ("shifts_id", "userId"); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -114,15 +114,16 @@ model Shift { | |
} | ||
|
||
model Signup { | ||
id Int @id @default(autoincrement()) | ||
shift Shift @relation(fields: [shiftId], references: [id]) | ||
shiftId Int @map("shifts_id") | ||
user User @relation(fields: [userId], references: [id]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another thought: we can just make the foreign key reference on the volunteers table rather than the base users table to enforce the "only volunteers can sign up" rule There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That also works but I think our middleware for checking the role is good enough for now. We would still need to go through each shift to check that the volunteerID is the same as the volunteerID associated with the user in the token. |
||
userId Int | ||
status SignupStatus | ||
numVolunteers Int @default(1) @map("num_volunteers") | ||
note String | ||
|
||
@@map("signups") | ||
@@id([shiftId, userId]) | ||
} | ||
|
||
model Volunteer { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { PrismaClient, Signup, SignupStatus } from "@prisma/client"; | ||
|
||
import IShiftSignupService from "../interfaces/shiftSignupService"; | ||
import { | ||
CreateShiftSignupDTO, | ||
ShiftSignupDTO, | ||
ShiftSignupResponseDTO, | ||
UpdateShiftSignupRequestDTO, | ||
} from "../../types"; | ||
import logger from "../../utilities/logger"; | ||
import { getErrorMessage } from "../../utilities/errorUtils"; | ||
|
||
const prisma = new PrismaClient(); | ||
|
||
const Logger = logger(__filename); | ||
|
||
class ShiftSignupService implements IShiftSignupService { | ||
convertSignupToDTO = (signup: Signup): ShiftSignupDTO => { | ||
return { | ||
...signup, | ||
shiftId: String(signup.shiftId), | ||
userId: String(signup.userId), | ||
}; | ||
}; | ||
|
||
async getShiftSignupsForUser( | ||
userId: string, | ||
): Promise<ShiftSignupResponseDTO[]> { | ||
try { | ||
const shiftSignups = await prisma.signup.findMany({ | ||
where: { userId: Number(userId) }, | ||
}); | ||
return shiftSignups.map((signup) => this.convertSignupToDTO(signup)); | ||
} catch (error: unknown) { | ||
Logger.error( | ||
`Failed to shift signups. Reason = ${getErrorMessage(error)}`, | ||
); | ||
throw error; | ||
} | ||
} | ||
|
||
async createShiftSignups( | ||
hujoseph99 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
shiftSignups: CreateShiftSignupDTO[], | ||
): Promise<ShiftSignupResponseDTO[]> { | ||
try { | ||
const newShiftSignups = await prisma.$transaction( | ||
shiftSignups.map((shiftSignup) => | ||
prisma.signup.create({ | ||
data: { | ||
...shiftSignup, | ||
shiftId: Number(shiftSignup.shiftId), | ||
userId: Number(shiftSignup.userId), | ||
status: SignupStatus.PENDING, | ||
}, | ||
}), | ||
), | ||
); | ||
return newShiftSignups.map((newShiftSignup) => | ||
this.convertSignupToDTO(newShiftSignup), | ||
); | ||
} catch (error: unknown) { | ||
Logger.error( | ||
`Failed to create shift signup. Reason = ${getErrorMessage(error)}`, | ||
); | ||
throw error; | ||
} | ||
} | ||
|
||
async updateShiftSignup( | ||
shiftId: string, | ||
userId: string, | ||
shiftSignup: UpdateShiftSignupRequestDTO, | ||
): Promise<ShiftSignupResponseDTO> { | ||
try { | ||
const updateResult = await prisma.signup.update({ | ||
where: { | ||
shiftId_userId: { | ||
shiftId: Number(shiftId), | ||
userId: Number(userId), | ||
}, | ||
}, | ||
data: shiftSignup, | ||
}); | ||
return this.convertSignupToDTO(updateResult); | ||
} catch (error: unknown) { | ||
Logger.error( | ||
`Failed to update shift signup. Reason = ${getErrorMessage(error)}`, | ||
); | ||
throw error; | ||
} | ||
} | ||
} | ||
|
||
export default ShiftSignupService; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { | ||
CreateShiftSignupDTO, | ||
ShiftSignupResponseDTO, | ||
UpdateShiftSignupRequestDTO, | ||
} from "../../types"; | ||
|
||
interface IShiftSignupService { | ||
/** | ||
* Bulk creates sign ups for shifts | ||
* @param shiftSignups array of CreateShiftSignupDTOs | ||
* @returns an array of ShiftSignupResponseDTO | ||
* @throws Error if any of the shifts signups cannot be created | ||
*/ | ||
createShiftSignups( | ||
shiftSignups: CreateShiftSignupDTO[], | ||
): Promise<ShiftSignupResponseDTO[]>; | ||
|
||
/** | ||
* Update a shift signup entry | ||
* @param shiftId the shift to update | ||
* @param userId the user to update | ||
* @param shiftSignup the information to be updated | ||
* @returns a ShiftSignupResponseDTO containing the updated information | ||
* @throws Error if the shift signup | ||
*/ | ||
updateShiftSignup( | ||
shiftId: string, | ||
userId: string, | ||
shiftSignup: UpdateShiftSignupRequestDTO, | ||
): Promise<ShiftSignupResponseDTO>; | ||
|
||
/** | ||
* Gets all shifts the user has signed up for | ||
* @param userId the target user's id | ||
* @returns an array of ShiftSignupResponseDTOs for each shift the user signed up for | ||
* @throws Error if the shift signup retrieval fails | ||
*/ | ||
getShiftSignupsForUser(userId: string): Promise<ShiftSignupResponseDTO[]>; | ||
} | ||
|
||
export default IShiftSignupService; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we also want to check
isAuthorizedByUserId
here to check that the userid in the token is the same as the userid they are signingup the shift asThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added!