fix: resolve emoji reactions query and mutations for quote/vote actions - #442
fix: resolve emoji reactions query and mutations for quote/vote actions#442AegisX-dev wants to merge 3 commits into
Conversation
|
@AegisX-dev is attempting to deploy a commit to the Louis Girifalco's projects Team on Vercel. A member of the Team first needs to authorize it. |
motirebuma
left a comment
There was a problem hiding this comment.
Hey @AegisX-dev - the code base for the reaction system is looking good overall. The resolver structure, auth guards, and tests are all in order. A few security and polish items before merge.
What's good
-
Auth guards - both mutations check
context.user._idand throwUNAUTHENTICATEDwith appropriate GraphQL error extensions. Tested both authenticated and unauthorized cases. -
Frontend - optional chaining on
state.user.data?.idprevents crash when unauthenticated, andstopPropagation()on the reaction container fixes the card expansion bug. Both are simple one-liners. -
Tests - good coverage of query, create, update, and auth rejection scenarios.
Items to address
addActionReactiontrusts client-provideduserId. The mutation takesuserIdfromargs.reaction.userIdand passes it toReaction.create()directly. An authenticated user could add a reaction on another user's behalf. Usecontext.user._idinstead:
const rxn = await Reaction.create({
userId: context.user._id, // insecure to take userId from args
actionId: args.reaction.actionId,
emoji: args.reaction.emoji
});updateActionReactionneeds ownership guard. Any authenticated user could update any reaction by_id. Before updating, verify that the reaction belongs to the current user:
const existing = await Reaction.findById(args._id).lean();
if (!existing || existing.userId.toString() !== context.user._id.toString()) {
throw new GraphQLError('Not authorized', { extensions: { code: 'FORBIDDEN' } });
}-
Missing
deleteActionReactionmutation. Currently, users can add and update reactions, but not delete them. Need a mutation to remove a reaction. -
No guard in
addActionReactionagainst multiple reactions from the same user. A user could click "React" multiple times and create multiple identical reactions. Consider usingfindOneAndUpdate(..., { upsert: true })on(userId, actionId)index, or add a unique index on these fields.
Nit
The Reaction model already defines a static findByActionId method. The query resolver should use Reaction.findByActionId(args.actionId) rather than Reaction.find({ actionId: args.actionId }) - that way, if the implementation of findByActionId() changes in the future, the resolver will continue to work.
Thanks @AegisX-dev
motirebuma
left a comment
There was a problem hiding this comment.
Hi @AegisX-dev, superb! All of my comments are addressed, and the implementation looks good.
What is good
Security issues
addActionReaction makes use of context.user._id rather than the given userId in the arguments. updateActionReaction, as well as the new deleteActionReaction, now have ownership guarding, returning FORBIDDEN if the user is not the one who created the reaction.
Duplicate guard
The new addActionReaction uses findOneAndUpdate(..., { upsert: true }) on (userId, actionId) combo, and a { userId: 1, actionId: 1 } unique index on the model. A belt and suspenders approach.
Delete mutation
The new delete mutation has an auth guard, ownership check, a GraphQL schema mutation, and TypeScript type definition. The frontend also has the DELETE_ACTION_REACTION mutation.
Other type fixes
The static methods now return QueryWithHelpers<...> rather than Promise, so that .lean() can be chained on them. Good catch!
Model statics usage
Using Reaction.findByActionId() static method rather than the raw find().
Test coverage
All the tests are present and cover the happy path, ownership check rejection (FORBIDDEN), not-found, delete success, and the upsert in addActionReaction correctly uses context.user._id even if another userId is passed in arguments.
Frontend fixes
Optional chaining on the user store and stopPropagation() on the reaction container.
No issues.
thansk @AegisX-dev
Summary
Fixes RC1-016: Resolves emoji reaction rendering, query handling, and mutation persistence for quote and vote activity records.
Changes Made
Backend (
quotevote-backend)actionReactionsqueryaddActionReactionmutationupdateActionReactionmutationaddActionReaction,updateActionReaction) to server.ts and registeredreactionResolver.Frontend (
quotevote-frontend)Verification & Testing