-
Notifications
You must be signed in to change notification settings - Fork 0
Justinxue #6
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
base: main
Are you sure you want to change the base?
Conversation
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.
Not a fan of mocking your ORM. These should just be integration tests
| }); | ||
|
|
||
| it("returns 403 when user is not admin", async () => { | ||
| (isAdmin as Mock).mockResolvedValue(false); |
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.
You are mocking isAdmin, which is creating an implementation requirement that the routes use isAdmin to check permissions.
However, this may not necessarily be true. Instead, you should inject the request context with an admin user to make this more resilient and require the test to know less about the implementation
|
Also less about your code but your PR, I would shy away from using AI to generate the description. It's just a whole bunch of unnecessary detail that makes it annoying to read. Just include a summary of your changes, any big decisions you made (and why, if it's not obvious), and potential things you want a reviewer to focus on |
danielp1218
left a comment
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.
overall just clean up your code, the logic looks OK to me.
| const params = c.req.valid("param"); | ||
| const body = c.req.valid("json"); | ||
|
|
||
| const admin = await isAdmin(body.sessionToken); |
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.
just a note that this implementation is subject to change #4
| if (input.questions.length > 0) { | ||
| await db.insert(formQuestion).values( | ||
| input.questions.map((q) => ({ | ||
| formQuestionId: q.formQuestionId, |
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.
the database will auto-generate IDs, we definitely don't want to supply them with data the client sends. you can just remove this line.
| }); | ||
| } | ||
|
|
||
| // Delete children first (avoid FK issues) |
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 have cascading deletes set in our schema so this isn't needed
| await db.insert(formQuestion).values( | ||
| srcQuestions.map((q) => ({ | ||
| // generate a new id so we never collide if formQuestionId is globally unique | ||
| formQuestionId: crypto.randomUUID(), |
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.
DB will auto-generate, can get rid of this line
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.
It auto-generates formQuestionId or do you mean formId.
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.
i mean formQuestionId in the formQuestion table. We have it set up so every table’s surrogate key a.k.a the {table}Id will default to a random uuid.
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.
In the current schema it looks like only formId has a uuid default
| questions?: CreateFormQuestionInput[]; | ||
| } | ||
|
|
||
| export const createForm = async (input: CreateFormInput) => { |
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.
Also, you should wrap all the DB operations in this function within a transaction. (same with updateForm and cloneForm)
Conceptually, we want either all the DB operations to happen or all fail. It will result in wierd data integrity issues if a function fails halfway.
Forms API – Summary (Create / Clone / Update / Delete)
This PR completes the admin-only Forms management APIs and corresponding service logic, with full unit test coverage for the service layer.
✅ Implemented Endpoints
CREATE Form (Admin only)
POST
/api/seasons/{seasonCode}/formsCreates a new form for a season, optionally with questions.
sessionTokenformformQuestionrowsCLONE Form (Admin only)
POST
/api/seasons/{seasonCode}/forms/{formId}/cloneCreates a new form by cloning an existing one.
formIdformQuestionIdviacrypto.randomUUID()UPDATE Form (Admin only)
POST
/api/seasons/{seasonCode}/forms/{formId}Updates form metadata and optionally replaces questions.
openTime,closeTime,tagsDELETE Form (Admin only)
DELETE
/api/seasons/{seasonCode}/forms/{formId}Deletes a form and all associated questions.
formQuestionform🧠 Service Layer (
forms.service.ts)createFormcloneFormupdateFormdeleteFormAll database interactions:
tags,questions)handleDbErrorThe logic is intentionally self-contained and mirrors API behavior closely, so no additional explanation is required beyond the routes.
🧪 Tests
forms.service.tsℹ️ Notes
isAdmin(userId)DELETE → 204)hono-openapi✅ This PR completes all admin-side Forms mutation endpoints.