diff --git a/apps/backend/src/datasources/ReviewDataSource.ts b/apps/backend/src/datasources/ReviewDataSource.ts index d5d53290dd..367f5c8401 100644 --- a/apps/backend/src/datasources/ReviewDataSource.ts +++ b/apps/backend/src/datasources/ReviewDataSource.ts @@ -21,14 +21,16 @@ export interface ReviewDataSource { userId?: number, callId?: number, instrumentId?: number, - submitted?: number + submitted?: number, + active?: boolean ): Promise; getAllUsersReviews( fapIds: number[], userId?: number, callId?: number, instrumentId?: number, - submitted?: number + submitted?: number, + active?: boolean ): Promise; getAssignmentReview( fapId: number, diff --git a/apps/backend/src/datasources/postgres/ReviewDataSource.ts b/apps/backend/src/datasources/postgres/ReviewDataSource.ts index eb3e49f062..2b728aac7a 100644 --- a/apps/backend/src/datasources/postgres/ReviewDataSource.ts +++ b/apps/backend/src/datasources/postgres/ReviewDataSource.ts @@ -349,7 +349,8 @@ export default class PostgresReviewDataSource implements ReviewDataSource { userId?: number, callId?: number, instrumentId?: number, - status?: ReviewStatus + status?: ReviewStatus, + active?: boolean ): Promise { return database .select() @@ -378,6 +379,16 @@ export default class PostgresReviewDataSource implements ReviewDataSource { if (status !== undefined && status !== null) { qb.where('fap_reviews.status', status); } + + if (active) { + qb.join('proposals', { + 'proposals.proposal_pk': 'fap_reviews.proposal_pk', + }); + qb.join('call', { + 'call.call_id': 'proposals.call_id', + }); + qb.where('call.call_fap_review_ended', false); + } }) .whereIn('fap_id', fapIds) .distinctOn('fap_reviews.proposal_pk') @@ -414,7 +425,8 @@ export default class PostgresReviewDataSource implements ReviewDataSource { userId?: number, callId?: number, instrumentId?: number, - status?: ReviewStatus + status?: ReviewStatus, + active?: boolean ): Promise { return database .select('fapReviewsTemp.*') @@ -440,6 +452,16 @@ export default class PostgresReviewDataSource implements ReviewDataSource { if (status !== null && status !== undefined) { qb.where('fap_reviews.status', status); } + + if (active) { + qb.join('proposals', { + 'proposals.proposal_pk': 'fap_reviews.proposal_pk', + }); + qb.join('call', { + 'call.call_id': 'proposals.call_id', + }); + qb.where('call.call_fap_review_ended', false); + } }) .whereIn('fap_id', fapIds) .as('fapReviewsTemp') diff --git a/apps/backend/src/resolvers/types/User.ts b/apps/backend/src/resolvers/types/User.ts index 8b69c0ef6f..3767010019 100644 --- a/apps/backend/src/resolvers/types/User.ts +++ b/apps/backend/src/resolvers/types/User.ts @@ -114,9 +114,10 @@ export class UserResolver { @Arg('callId', () => Int, { nullable: true }) callId: number, @Arg('instrumentId', () => Int, { nullable: true }) instrumentId: number, @Arg('status', () => ReviewStatus, { nullable: true }) status: number, - @Arg('reviewer', () => ReviewerFilter, { nullable: true }) - reviewer: number, - @Ctx() context: ResolverContext + @Arg('reviewer', () => ReviewerFilter, { nullable: true }) reviewer: number, + @Arg('active', () => Boolean, { nullable: true }) active: boolean, + @Ctx() + context: ResolverContext ) { if (!context.user || !context.user.currentRole) { return []; @@ -136,7 +137,8 @@ export class UserResolver { user.id, callId, instrumentId, - status + status, + active ); } else { return context.queries.review.dataSource.getAllUsersReviews( @@ -144,7 +146,8 @@ export class UserResolver { user.id, callId, instrumentId, - status + status, + active ); } } diff --git a/apps/e2e/cypress/e2e/FAPs.cy.ts b/apps/e2e/cypress/e2e/FAPs.cy.ts index d8c6b7f376..786760963a 100644 --- a/apps/e2e/cypress/e2e/FAPs.cy.ts +++ b/apps/e2e/cypress/e2e/FAPs.cy.ts @@ -1816,6 +1816,31 @@ context('Fap reviews tests', () => { cy.contains(proposal1.title); cy.contains(proposal3.title); }); + it('Fap Reviewer should only be able to see proposals from calls with active fap review periods', () => { + cy.get('#reviewer-selection', { timeout: 5000 }) + .parent() + .should('be.visible') + .click(); + cy.get('[role="presentation"]').contains('My proposals').click(); + cy.finishedLoading(); + cy.contains(proposal1.title); + + cy.updateCall({ + id: initialDBData.call.id, + callFapReviewEnded: true, + }); + cy.reload(); + + cy.get('#reviewer-selection', { timeout: 5000 }) + .parent() + .should('be.visible') + .click(); + cy.get('[role="presentation"]').contains('My proposals').click(); + cy.finishedLoading(); + + cy.contains(proposal1.title).should('not.exist'); + }); + it('Fap Reviewer should not be able to submit a grade for proposals on which they are not reviewer, they should only able to view them', () => { cy.get('#reviewer-selection', { timeout: 5000 }) .parent() @@ -3836,7 +3861,6 @@ context('Fap meeting components tests', () => { cy.visit('/'); cy.get('main table tbody').contains('No records to display'); }); - it('Fap Reviewer should be able to give review', () => { cy.login(fapMembers.reviewer); cy.visit('/'); diff --git a/apps/frontend/src/components/review/ProposalTableReviewer.tsx b/apps/frontend/src/components/review/ProposalTableReviewer.tsx index 3e96bfd751..330294700b 100644 --- a/apps/frontend/src/components/review/ProposalTableReviewer.tsx +++ b/apps/frontend/src/components/review/ProposalTableReviewer.tsx @@ -116,6 +116,7 @@ const ProposalTableReviewer = ({ confirm }: { confirm: WithConfirmType }) => { instrumentId: selectedInstrumentId, status: getFilterStatus(reviewStatus), reviewer: getFilterReviewer(reviewer), + active: true, }); useEffect(() => { diff --git a/apps/frontend/src/graphql/review/userWithReviews.graphql b/apps/frontend/src/graphql/review/userWithReviews.graphql index cc8874e503..8b9482bc20 100644 --- a/apps/frontend/src/graphql/review/userWithReviews.graphql +++ b/apps/frontend/src/graphql/review/userWithReviews.graphql @@ -3,6 +3,7 @@ query userWithReviews( $instrumentId: Int $status: ReviewStatus $reviewer: ReviewerFilter + $active: Boolean ) { me { id @@ -14,6 +15,7 @@ query userWithReviews( instrumentId: $instrumentId status: $status reviewer: $reviewer + active: $active ) { id grade diff --git a/apps/frontend/src/hooks/user/useUserData.ts b/apps/frontend/src/hooks/user/useUserData.ts index 372e6a9788..85c84dee29 100644 --- a/apps/frontend/src/hooks/user/useUserData.ts +++ b/apps/frontend/src/hooks/user/useUserData.ts @@ -61,6 +61,7 @@ export function useUserWithReviewsData(filters?: { instrumentId?: number | null; status?: ReviewStatus; reviewer?: ReviewerFilter; + active?: boolean; }) { const api = useDataApi(); const [userWithReviewsFilter, setUserWithReviewsFilter] = useState(filters);