From db156d8f74064a57b0fde10061b2b482dac21efd Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 20:24:30 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=B9=20[code=20health=20improvement]=20?= =?UTF-8?q?Validate=20resolver=20same=20organization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/server/db/query/doubt.sql | 12 +++++++++ apps/server/internal/db/sqlc/doubt.sql.go | 25 +++++++++++++++++++ apps/server/internal/db/sqlc/querier.go | 1 + .../internal/modules/progress/service.go | 14 ++++++++--- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/apps/server/db/query/doubt.sql b/apps/server/db/query/doubt.sql index 5526f01..73f90e4 100644 --- a/apps/server/db/query/doubt.sql +++ b/apps/server/db/query/doubt.sql @@ -176,3 +176,15 @@ JOIN users u ON om.user_id = u.id JOIN bootcamp_enrollments be ON a.bootcamp_enrollment_id = be.id WHERE be.bootcamp_id = $1 AND d.resolved = FALSE ORDER BY d.created_at ASC; + +-- name: CheckResolverSameOrganization :one +SELECT EXISTS( + SELECT 1 + FROM doubts d + JOIN assignment_problems ap ON d.assignment_problem_id = ap.id + JOIN assignments a ON ap.assignment_id = a.id + JOIN bootcamp_enrollments be ON a.bootcamp_enrollment_id = be.id + JOIN bootcamps b ON be.bootcamp_id = b.id + JOIN organization_members resolver ON resolver.id = $2 + WHERE d.id = $1 AND b.organization_id = resolver.organization_id +) AS is_same_org; diff --git a/apps/server/internal/db/sqlc/doubt.sql.go b/apps/server/internal/db/sqlc/doubt.sql.go index 007c3f4..22b6fc7 100644 --- a/apps/server/internal/db/sqlc/doubt.sql.go +++ b/apps/server/internal/db/sqlc/doubt.sql.go @@ -749,3 +749,28 @@ func (q *Queries) ValidateAssignmentProblemOwnership(ctx context.Context, arg Va err := row.Scan(&is_owner) return is_owner, err } + +const checkResolverSameOrganization = `-- name: CheckResolverSameOrganization :one +SELECT EXISTS( + SELECT 1 + FROM doubts d + JOIN assignment_problems ap ON d.assignment_problem_id = ap.id + JOIN assignments a ON ap.assignment_id = a.id + JOIN bootcamp_enrollments be ON a.bootcamp_enrollment_id = be.id + JOIN bootcamps b ON be.bootcamp_id = b.id + JOIN organization_members resolver ON resolver.id = $2 + WHERE d.id = $1 AND b.organization_id = resolver.organization_id +) AS is_same_org +` + +type CheckResolverSameOrganizationParams struct { + ID pgtype.UUID `db:"id" json:"id"` + ID_2 pgtype.UUID `db:"id_2" json:"id_2"` +} + +func (q *Queries) CheckResolverSameOrganization(ctx context.Context, arg CheckResolverSameOrganizationParams) (bool, error) { + row := q.db.QueryRow(ctx, checkResolverSameOrganization, arg.ID, arg.ID_2) + var is_same_org bool + err := row.Scan(&is_same_org) + return is_same_org, err +} diff --git a/apps/server/internal/db/sqlc/querier.go b/apps/server/internal/db/sqlc/querier.go index 51f8cc5..1036564 100644 --- a/apps/server/internal/db/sqlc/querier.go +++ b/apps/server/internal/db/sqlc/querier.go @@ -159,6 +159,7 @@ type Querier interface { UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error) UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) error UpsertLeaderboardEntry(ctx context.Context, arg UpsertLeaderboardEntryParams) (LeaderboardEntry, error) + CheckResolverSameOrganization(ctx context.Context, arg CheckResolverSameOrganizationParams) (bool, error) ValidateAssignmentProblemOwnership(ctx context.Context, arg ValidateAssignmentProblemOwnershipParams) (bool, error) } diff --git a/apps/server/internal/modules/progress/service.go b/apps/server/internal/modules/progress/service.go index 672968a..d2239f7 100644 --- a/apps/server/internal/modules/progress/service.go +++ b/apps/server/internal/modules/progress/service.go @@ -218,9 +218,17 @@ func (s *Service) ResolveDoubt(ctx context.Context, doubtID, resolvedByMemberID return mapDoubtWithDetailsToData(&doubtWithDetails), nil } - // TODO: Validate resolver belongs to same organization - // This would require joining through assignment_problems -> assignments -> bootcamp_enrollments - // For now, we trust the handler to enforce this through role checks + // Validate resolver belongs to same organization + isSameOrg, err := s.queries.CheckResolverSameOrganization(ctx, db.CheckResolverSameOrganizationParams{ + ID: doubtID, + ID_2: resolvedByMemberID, + }) + if err != nil { + return nil, err + } + if !isSameOrg { + return nil, errors.New("RESOLVER_NOT_IN_SAME_ORGANIZATION") + } // Set resolved to true, resolved_by, resolved_at doubt, err := s.queries.ResolveDoubt(ctx, db.ResolveDoubtParams{