From e740bd164e8adc791b40ac838a585a19f7abe3e5 Mon Sep 17 00:00:00 2001 From: Will Franklin Date: Thu, 5 Dec 2024 11:05:41 +0100 Subject: [PATCH 1/3] Don't allow non-reviewers to export --- .../BaseCalloutResponseTransformer.ts | 18 +----------------- .../transformers/CalloutResponseExporter.ts | 13 ++++++++++++- .../transformers/CalloutResponseTransformer.ts | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/apps/backend/src/api/transformers/BaseCalloutResponseTransformer.ts b/apps/backend/src/api/transformers/BaseCalloutResponseTransformer.ts index dcc183654..ef961eae3 100644 --- a/apps/backend/src/api/transformers/BaseCalloutResponseTransformer.ts +++ b/apps/backend/src/api/transformers/BaseCalloutResponseTransformer.ts @@ -14,9 +14,8 @@ import { mergeRules } from "@beabee/core/utils/rules"; import { CalloutResponse } from "@beabee/core/models"; -import { AuthInfo, FilterHandlers } from "@beabee/core/type"; +import { FilterHandlers } from "@beabee/core/type"; import { calloutResponseFilterHandlers } from "@beabee/core/filter-handlers"; -import { getReviewerRules } from "@api/utils/callouts"; export abstract class BaseCalloutResponseTransformer< GetDto, @@ -43,21 +42,6 @@ export abstract class BaseCalloutResponseTransformer< ]; } - protected async getNonAdminAuthRules( - auth: AuthInfo, - query: GetOptsDto - ): Promise { - return { - condition: "OR", - rules: [ - // User's can always see their own responses - { field: "contact", operator: "equal", value: ["me"] }, - // And any responses for callouts they are reviewers for - ...(await getReviewerRules(auth.contact, "calloutId")) - ] - }; - } - protected transformQuery(query: T): T { return { ...query, diff --git a/apps/backend/src/api/transformers/CalloutResponseExporter.ts b/apps/backend/src/api/transformers/CalloutResponseExporter.ts index a9e26a1ea..e84ed8fea 100644 --- a/apps/backend/src/api/transformers/CalloutResponseExporter.ts +++ b/apps/backend/src/api/transformers/CalloutResponseExporter.ts @@ -1,5 +1,6 @@ import { RoleType, + RuleGroup, getCalloutComponents, stringifyAnswer } from "@beabee/beabee-common"; @@ -16,7 +17,7 @@ import { } from "@api/dto/CalloutResponseDto"; import { BaseCalloutResponseTransformer } from "@api/transformers/BaseCalloutResponseTransformer"; import { NotFoundError } from "@beabee/core/errors"; -import { groupBy } from "@api/utils"; +import { getReviewerRules, groupBy } from "@api/utils"; import { CalloutResponse, @@ -59,6 +60,16 @@ class CalloutResponseExporter extends BaseCalloutResponseTransformer< ]; } + protected async getNonAdminAuthRules( + auth: AuthInfo, + query: ExportCalloutResponsesOptsDto + ): Promise { + const reviewerRules = await getReviewerRules(auth.contact, "calloutId"); + return reviewerRules.length + ? { condition: "OR", rules: reviewerRules } + : false; + } + protected modifyQueryBuilder( qb: SelectQueryBuilder, fieldPrefix: string diff --git a/apps/backend/src/api/transformers/CalloutResponseTransformer.ts b/apps/backend/src/api/transformers/CalloutResponseTransformer.ts index b80162967..75cdbf2c9 100644 --- a/apps/backend/src/api/transformers/CalloutResponseTransformer.ts +++ b/apps/backend/src/api/transformers/CalloutResponseTransformer.ts @@ -31,6 +31,8 @@ import { } from "@beabee/core/models"; import { AuthInfo } from "@beabee/core/type"; +import { RuleGroup } from "@beabee/beabee-common"; +import { getReviewerRules } from "@api/utils"; export class CalloutResponseTransformer extends BaseCalloutResponseTransformer< GetCalloutResponseDto, @@ -80,6 +82,21 @@ export class CalloutResponseTransformer extends BaseCalloutResponseTransformer< }; } + protected async getNonAdminAuthRules( + auth: AuthInfo, + query: GetCalloutResponseOptsDto + ): Promise { + return { + condition: "OR", + rules: [ + // User's can always see their own responses + { field: "contact", operator: "equal", value: ["me"] }, + // And any responses for callouts they are reviewers for + ...(await getReviewerRules(auth.contact, "calloutId")) + ] + }; + } + protected modifyQueryBuilder( qb: SelectQueryBuilder, fieldPrefix: string, From 3835a25c3a8379428ed2d00f28c10a16f53a2fcf Mon Sep 17 00:00:00 2001 From: Will Franklin Date: Thu, 5 Dec 2024 11:22:23 +0100 Subject: [PATCH 2/3] Remove duplicate method definition (can inherit from parent) --- .../CalloutResponseMapTransformer.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/apps/backend/src/api/transformers/CalloutResponseMapTransformer.ts b/apps/backend/src/api/transformers/CalloutResponseMapTransformer.ts index 665506412..aa4753c37 100644 --- a/apps/backend/src/api/transformers/CalloutResponseMapTransformer.ts +++ b/apps/backend/src/api/transformers/CalloutResponseMapTransformer.ts @@ -15,7 +15,6 @@ import { getRepository } from "@beabee/core/database"; import { GetCalloutResponseMapDto, GetCalloutResponseMapOptsDto, - ListCalloutResponseMapDto, ListCalloutResponsesDto } from "@api/dto/CalloutResponseDto"; import { PaginatedDto } from "@api/dto/PaginatedDto"; @@ -24,8 +23,6 @@ import { BaseCalloutResponseTransformer } from "@api/transformers/BaseCalloutRes import { Callout, CalloutResponse } from "@beabee/core/models"; -import { mergeRules } from "@beabee/core/utils/rules"; - import { AuthInfo } from "@beabee/core/type"; class CalloutResponseMapTransformer extends BaseCalloutResponseTransformer< @@ -100,21 +97,6 @@ class CalloutResponseMapTransformer extends BaseCalloutResponseTransformer< }; } - protected transformQuery(query: T): T { - return { - ...query, - rules: mergeRules([ - query.rules, - // Only load responses for the given callout - { - field: "calloutId", - operator: "equal", - value: [query.callout.id] - } - ]) - }; - } - /** * Fetch the responses for a specific callout. The transformer needs the * callout's response view schema to determine how to transform the responses. From d88c6d6fc57a9b29fc7511ece80dbc621356cf74 Mon Sep 17 00:00:00 2001 From: Will Franklin Date: Thu, 5 Dec 2024 11:23:11 +0100 Subject: [PATCH 3/3] Only load assignee for reviewers or admins --- apps/backend/src/api/dto/CalloutResponseDto.ts | 1 + .../api/transformers/CalloutResponseTransformer.ts | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/backend/src/api/dto/CalloutResponseDto.ts b/apps/backend/src/api/dto/CalloutResponseDto.ts index 26d0c6af7..7a073c9ab 100644 --- a/apps/backend/src/api/dto/CalloutResponseDto.ts +++ b/apps/backend/src/api/dto/CalloutResponseDto.ts @@ -36,6 +36,7 @@ import { Callout } from "@beabee/core/models"; export interface BaseGetCalloutResponseOptsDto { callout?: Callout; + isReviewer?: boolean; } export enum GetCalloutResponseWith { diff --git a/apps/backend/src/api/transformers/CalloutResponseTransformer.ts b/apps/backend/src/api/transformers/CalloutResponseTransformer.ts index 75cdbf2c9..c87543504 100644 --- a/apps/backend/src/api/transformers/CalloutResponseTransformer.ts +++ b/apps/backend/src/api/transformers/CalloutResponseTransformer.ts @@ -86,13 +86,18 @@ export class CalloutResponseTransformer extends BaseCalloutResponseTransformer< auth: AuthInfo, query: GetCalloutResponseOptsDto ): Promise { + const reviewerRules = await getReviewerRules(auth.contact, "calloutId"); + + // This is a hacky way to pass the reviewer status to modifyQueryBuilder + query.isReviewer = reviewerRules.length > 0; + return { condition: "OR", rules: [ // User's can always see their own responses { field: "contact", operator: "equal", value: ["me"] }, // And any responses for callouts they are reviewers for - ...(await getReviewerRules(auth.contact, "calloutId")) + ...reviewerRules ] }; } @@ -103,8 +108,10 @@ export class CalloutResponseTransformer extends BaseCalloutResponseTransformer< query: ListCalloutResponsesDto, auth: AuthInfo ): void { - // TODO: Add auth check for assignee - if (query.with?.includes(GetCalloutResponseWith.Assignee)) { + if ( + query.with?.includes(GetCalloutResponseWith.Assignee) && + (query.isReviewer || auth.roles.includes("admin")) + ) { qb.leftJoinAndSelect(`${fieldPrefix}assignee`, "assignee"); } if (query.with?.includes(GetCalloutResponseWith.Callout)) {