From a1168336592249c3ceeb1b493abc557b3f868e19 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Mon, 4 Dec 2023 18:10:14 +0800 Subject: [PATCH 1/2] feat: allow moving items to a folder in a bulk --- packages/api/src/generated/graphql.ts | 4 +- packages/api/src/generated/schema.graphql | 3 +- packages/api/src/resolvers/article/index.ts | 64 +++++++++++---------- packages/api/src/schema.ts | 2 + packages/api/src/services/library_item.ts | 26 ++++++++- 5 files changed, 65 insertions(+), 34 deletions(-) diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index 5b767e76e..c50b7510f 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -245,7 +245,8 @@ export enum BulkActionType { AddLabels = 'ADD_LABELS', Archive = 'ARCHIVE', Delete = 'DELETE', - MarkAsRead = 'MARK_AS_READ' + MarkAsRead = 'MARK_AS_READ', + MoveToFolder = 'MOVE_TO_FOLDER' } export enum ContentReader { @@ -1376,6 +1377,7 @@ export type MutationAddPopularReadArgs = { export type MutationBulkActionArgs = { action: BulkActionType; + arguments?: InputMaybe; async?: InputMaybe; expectedCount?: InputMaybe; labelIds?: InputMaybe>; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index cb75551cc..7a426ab80 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -204,6 +204,7 @@ enum BulkActionType { ARCHIVE DELETE MARK_AS_READ + MOVE_TO_FOLDER } enum ContentReader { @@ -1170,7 +1171,7 @@ type MoveToFolderSuccess { type Mutation { addPopularRead(name: String!): AddPopularReadResult! - bulkAction(action: BulkActionType!, async: Boolean, expectedCount: Int, labelIds: [ID!], query: String!): BulkActionResult! + bulkAction(action: BulkActionType!, arguments: JSON, async: Boolean, expectedCount: Int, labelIds: [ID!], query: String!): BulkActionResult! createArticle(input: CreateArticleInput!): CreateArticleResult! createArticleSavingRequest(input: CreateArticleSavingRequestInput!): CreateArticleSavingRequestResult! createGroup(input: CreateGroupInput!): CreateGroupResult! diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index 1cc84dcdc..585d98a16 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -810,41 +810,47 @@ export const bulkActionResolver = authorized< BulkActionSuccess, BulkActionError, MutationBulkActionArgs ->(async (_parent, { query, action, labelIds }, { uid, log }) => { - try { - analytics.track({ - userId: uid, - event: 'BulkAction', - properties: { - env: env.server.apiEnv, - action, - }, - }) +>( + async ( + _parent, + { query, action, labelIds, arguments: args }, // arguments is a reserved keyword in JS + { uid, log } + ) => { + try { + analytics.track({ + userId: uid, + event: 'BulkAction', + properties: { + env: env.server.apiEnv, + action, + }, + }) - // parse query - const searchQuery = parseSearchQuery(query) - if (searchQuery.ids.length > 100) { - return { errorCodes: [BulkActionErrorCode.BadRequest] } - } - - // get labels if needed - let labels = undefined - if (action === BulkActionType.AddLabels) { - if (!labelIds || labelIds.length === 0) { + // parse query + const searchQuery = parseSearchQuery(query) + if (searchQuery.ids.length > 100) { return { errorCodes: [BulkActionErrorCode.BadRequest] } } - labels = await findLabelsByIds(labelIds, uid) + // get labels if needed + let labels = undefined + if (action === BulkActionType.AddLabels) { + if (!labelIds || labelIds.length === 0) { + return { errorCodes: [BulkActionErrorCode.BadRequest] } + } + + labels = await findLabelsByIds(labelIds, uid) + } + + await updateLibraryItems(action, searchQuery, uid, labels, args) + + return { success: true } + } catch (error) { + log.error('bulkActionResolver error', error) + return { errorCodes: [BulkActionErrorCode.BadRequest] } } - - await updateLibraryItems(action, searchQuery, uid, labels) - - return { success: true } - } catch (error) { - log.error('bulkActionResolver error', error) - return { errorCodes: [BulkActionErrorCode.BadRequest] } } -}) +) export const setFavoriteArticleResolver = authorized< SetFavoriteArticleSuccess, diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index 94a759f92..4078c8652 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -2510,6 +2510,7 @@ const schema = gql` ARCHIVE MARK_AS_READ ADD_LABELS + MOVE_TO_FOLDER } union BulkActionResult = BulkActionSuccess | BulkActionError @@ -2800,6 +2801,7 @@ const schema = gql` labelIds: [ID!] expectedCount: Int # max number of items to process async: Boolean # if true, return immediately and process in the background + arguments: JSON # additional arguments for the action ): BulkActionResult! importFromIntegration(integrationId: ID!): ImportFromIntegrationResult! setFavoriteArticle(id: ID!): SetFavoriteArticleResult! diff --git a/packages/api/src/services/library_item.ts b/packages/api/src/services/library_item.ts index dbb0a0998..e809cfbbf 100644 --- a/packages/api/src/services/library_item.ts +++ b/packages/api/src/services/library_item.ts @@ -671,10 +671,19 @@ export const countByCreatedAt = async ( export const updateLibraryItems = async ( action: BulkActionType, - args: SearchArgs, + searchArgs: SearchArgs, userId: string, - labels?: Label[] + labels?: Label[], + args?: unknown ) => { + interface FolderArguments { + folder: string + } + + const isFolderArguments = (args: any): args is FolderArguments => { + return 'folder' in args + } + // build the script let values: QueryDeepPartialEntity = {} let addLabels = false @@ -700,6 +709,17 @@ export const updateLibraryItems = async ( readingProgressTopPercent: 100, readingProgressBottomPercent: 100, } + break + case BulkActionType.MoveToFolder: + if (!args || !isFolderArguments(args)) { + throw new Error('Invalid arguments') + } + + values = { + folder: args.folder, + savedAt: new Date(), + } + break default: throw new Error('Invalid bulk action') @@ -711,7 +731,7 @@ export const updateLibraryItems = async ( .where('library_item.user_id = :userId', { userId }) // build the where clause - buildWhereClause(queryBuilder, args) + buildWhereClause(queryBuilder, searchArgs) if (addLabels) { if (!labels) { From 120fe19dab0b8af26ae1c0db8efd19f73b20c990 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Mon, 4 Dec 2023 18:53:46 +0800 Subject: [PATCH 2/2] fix typo --- packages/api/src/utils/auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/src/utils/auth.ts b/packages/api/src/utils/auth.ts index d430dd15a..49c5fe9ff 100644 --- a/packages/api/src/utils/auth.ts +++ b/packages/api/src/utils/auth.ts @@ -137,7 +137,7 @@ export const isSystemRequest = (req: express.Request): boolean => { try { const claims = jwt.verify(token, env.server.jwtSecret) as Claims - return !claims.system + return !!claims.system } catch (e) { return false }