diff --git a/packages/api/src/resolvers/folder_policy/index.ts b/packages/api/src/resolvers/folder_policy/index.ts index 737d655e2..434133cbd 100644 --- a/packages/api/src/resolvers/folder_policy/index.ts +++ b/packages/api/src/resolvers/folder_policy/index.ts @@ -1,14 +1,21 @@ import { FolderPolicy, FolderPolicyAction } from '../../entity/folder_policy' import { CreateFolderPolicyError, + CreateFolderPolicyErrorCode, CreateFolderPolicySuccess, FolderPoliciesError, FolderPoliciesSuccess, MutationCreateFolderPolicyArgs, + MutationUpdateFolderPolicyArgs, + UpdateFolderPolicyError, + UpdateFolderPolicyErrorCode, + UpdateFolderPolicySuccess, } from '../../generated/graphql' import { createFolderPolicy, findFolderPoliciesByUserId, + findFolderPolicyById, + updateFolderPolicy, } from '../../services/folder_policy' import { Merge } from '../../util' import { authorized } from '../../utils/gql-utils' @@ -35,6 +42,12 @@ export const createFolderPolicyResolver = authorized< >(async (_, { input }, { uid }) => { const { folder, action, afterDays, minimumItems } = input + if (afterDays < 0 || (minimumItems && minimumItems < 0)) { + return { + errorCodes: [CreateFolderPolicyErrorCode.BadRequest], + } + } + const policy = await createFolderPolicy({ userId: uid, folder, @@ -47,3 +60,46 @@ export const createFolderPolicyResolver = authorized< policy, } }) + +export const updateFolderPolicyResolver = authorized< + Merge, + UpdateFolderPolicyError, + MutationUpdateFolderPolicyArgs +>(async (_, { input }, { uid }) => { + const { id, action, afterDays, minimumItems } = input + + if (!action && !afterDays && !minimumItems) { + return { + errorCodes: [UpdateFolderPolicyErrorCode.BadRequest], + } + } + + if ((afterDays && afterDays < 0) || (minimumItems && minimumItems < 0)) { + return { + errorCodes: [UpdateFolderPolicyErrorCode.BadRequest], + } + } + + const result = await updateFolderPolicy(uid, id, { + action: action ? (action as unknown as FolderPolicyAction) : undefined, + afterDays: afterDays ?? undefined, + minimumItems: minimumItems ?? undefined, + }) + + if (!result.affected) { + return { + errorCodes: [UpdateFolderPolicyErrorCode.Unauthorized], + } + } + + const policy = await findFolderPolicyById(uid, id) + if (!policy) { + return { + errorCodes: [UpdateFolderPolicyErrorCode.Unauthorized], + } + } + + return { + policy, + } +}) diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index 21a5d4d78..89c885500 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -55,6 +55,7 @@ import { optInFeatureResolver } from './features' import { createFolderPolicyResolver, folderPoliciesResolver, + updateFolderPolicyResolver, } from './folder_policy' import { highlightsResolver } from './highlight' import { @@ -312,6 +313,7 @@ export const functionResolvers = { replyToEmail: replyToEmailResolver, refreshHome: refreshHomeResolver, createFolderPolicy: createFolderPolicyResolver, + updateFolderPolicy: updateFolderPolicyResolver, }, Query: { me: getMeUserResolver, @@ -888,4 +890,5 @@ export const functionResolvers = { ...resultResolveTypeResolver('Highlights'), ...resultResolveTypeResolver('FolderPolicies'), ...resultResolveTypeResolver('CreateFolderPolicy'), + ...resultResolveTypeResolver('UpdateFolderPolicy'), } diff --git a/packages/api/src/services/folder_policy.ts b/packages/api/src/services/folder_policy.ts index b4477a6be..6358c5784 100644 --- a/packages/api/src/services/folder_policy.ts +++ b/packages/api/src/services/folder_policy.ts @@ -19,20 +19,33 @@ export const findFolderPoliciesByUserId = async (userId: string) => { } export const updateFolderPolicy = async ( - id: string, + userId: string, + folderPolicyId: string, update: Partial ) => { - return getRepository(FolderPolicy).update(id, update) + return getRepository(FolderPolicy).update( + { id: folderPolicyId, userId }, + update + ) } -export const deleteFolderPolicy = async (id: string) => { - return getRepository(FolderPolicy).delete(id) +export const deleteFolderPolicy = async ( + userId: string, + folderPolicyId: string +) => { + return getRepository(FolderPolicy).delete({ + id: folderPolicyId, + userId, + }) } export const findFolderPolicies = async () => { return getRepository(FolderPolicy).find() } -export const findFolderPolicyById = async (id: string) => { - return getRepository(FolderPolicy).findOneBy({ id }) +export const findFolderPolicyById = async ( + userId: string, + folderPolicyId: string +) => { + return getRepository(FolderPolicy).findOneBy({ id: folderPolicyId, userId }) } diff --git a/packages/api/test/resolvers/folder_policy.test.ts b/packages/api/test/resolvers/folder_policy.test.ts index f4d30925a..3612685e3 100644 --- a/packages/api/test/resolvers/folder_policy.test.ts +++ b/packages/api/test/resolvers/folder_policy.test.ts @@ -1,5 +1,8 @@ import { expect } from 'chai' -import { FolderPolicyAction } from '../../src/entity/folder_policy' +import { + FolderPolicy as FolderPolicyEntity, + FolderPolicyAction, +} from '../../src/entity/folder_policy' import { User } from '../../src/entity/user' import { FolderPolicy } from '../../src/generated/graphql' import { @@ -60,7 +63,7 @@ describe('Folder Policy API', () => { expect(policies).to.have.lengthOf(1) expect(policies[0].id).to.equal(existingPolicy.id) - await deleteFolderPolicy(existingPolicy.id) + await deleteFolderPolicy(loginUser.id, existingPolicy.id) }) }) @@ -99,11 +102,68 @@ describe('Folder Policy API', () => { const createdPolicy = res.body.data.createFolderPolicy .policy as FolderPolicy - const policy = await findFolderPolicyById(createdPolicy.id) + const policy = await findFolderPolicyById(loginUser.id, createdPolicy.id) expect(policy).to.exist expect(policy?.folder).to.equal(input.folder) - await deleteFolderPolicy(createdPolicy.id) + await deleteFolderPolicy(loginUser.id, createdPolicy.id) + }) + }) + + describe('Update Folder Policy', () => { + let existingPolicy: FolderPolicyEntity + + before(async () => { + existingPolicy = await createFolderPolicy({ + userId: loginUser.id, + folder: 'test-folder', + action: FolderPolicyAction.ARCHIVE, + afterDays: 30, + minimumItems: 10, + }) + }) + + after(async () => { + await deleteFolderPolicy(loginUser.id, existingPolicy.id) + }) + + const mutation = ` + mutation UpdateFolderPolicy($input: UpdateFolderPolicyInput!) { + updateFolderPolicy(input: $input) { + ... on UpdateFolderPolicySuccess { + policy { + id + folder + action + createdAt + updatedAt + } + } + ... on UpdateFolderPolicyError { + errorCodes + } + } + } + ` + + it('should update a folder policy', async () => { + const input = { + id: existingPolicy.id, + action: FolderPolicyAction.DELETE, + afterDays: 30, + minimumItems: 10, + } + + const res = await graphqlRequest(mutation, authToken, { input }).expect( + 200 + ) + + const updatedPolicy = res.body.data.updateFolderPolicy + .policy as FolderPolicy + + const policy = await findFolderPolicyById(loginUser.id, updatedPolicy.id) + expect(policy).to.exist + expect(policy?.action).to.equal(input.action) }) }) })