From dcd6e8bb6039452485fa243a07865c0e7aece074 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Wed, 13 Dec 2023 16:25:25 +0800 Subject: [PATCH] allow adding source of label when adding labels --- packages/api/src/entity/entity_label.ts | 14 +++++- packages/api/src/generated/graphql.ts | 1 + packages/api/src/generated/schema.graphql | 1 + packages/api/src/resolvers/article/index.ts | 3 +- packages/api/src/resolvers/labels/index.ts | 20 +++++++- packages/api/src/routers/svc/following.ts | 4 +- packages/api/src/schema.ts | 1 + packages/api/src/services/labels.ts | 54 ++++++++++----------- packages/api/src/services/save_email.ts | 10 ++-- 9 files changed, 69 insertions(+), 39 deletions(-) diff --git a/packages/api/src/entity/entity_label.ts b/packages/api/src/entity/entity_label.ts index 53cd45f4d..44e061faa 100644 --- a/packages/api/src/entity/entity_label.ts +++ b/packages/api/src/entity/entity_label.ts @@ -1,5 +1,15 @@ import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm' +// for labels created by rules, we use the rule name as the source, for example: 'rule:my-rule' +// for labels created by users, we use 'user' +// for labels created by system, we use 'system' +type RuleSourceType = `rule:${string}` +export type LabelSource = 'user' | 'system' | RuleSourceType + +export const isLabelSource = (source: string): source is LabelSource => { + return ['user', 'system'].indexOf(source) !== -1 || source.startsWith('rule:') +} + @Entity({ name: 'entity_labels' }) export class EntityLabel { @PrimaryGeneratedColumn('uuid') @@ -14,6 +24,6 @@ export class EntityLabel { @Column('uuid') highlightId?: string | null - @Column('text') - source!: string + @Column('text', { default: 'user' }) + source!: LabelSource } diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index 57bd61997..c015e3a43 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -2539,6 +2539,7 @@ export type SetLabelsInput = { labelIds?: InputMaybe>; labels?: InputMaybe>; pageId: Scalars['ID']; + source?: InputMaybe; }; export type SetLabelsResult = SetLabelsError | SetLabelsSuccess; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index 8f64a27b7..1dc9c76b0 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -1971,6 +1971,7 @@ input SetLabelsInput { labelIds: [ID!] labels: [CreateLabelInput!] pageId: ID! + source: String } union SetLabelsResult = SetLabelsError | SetLabelsSuccess diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index 08f156690..cc373cbfc 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -359,8 +359,7 @@ export const createArticleResolver = authorized< libraryItemToReturn.id, uid, inputLabels, - rssFeedUrl, - pubsub + rssFeedUrl ) log.info( diff --git a/packages/api/src/resolvers/labels/index.ts b/packages/api/src/resolvers/labels/index.ts index 27cd0ab25..5e6e77c5a 100644 --- a/packages/api/src/resolvers/labels/index.ts +++ b/packages/api/src/resolvers/labels/index.ts @@ -1,4 +1,5 @@ import { Between } from 'typeorm' +import { isLabelSource, LabelSource } from '../../entity/entity_label' import { Label } from '../../entity/label' import { env } from '../../env' import { @@ -160,7 +161,7 @@ export const setLabelsResolver = authorized< >( async ( _, - { input: { pageId, labelIds, labels } }, + { input: { pageId, labelIds, labels, source } }, { uid, log, authTrx, pubsub } ) => { if (!labelIds && !labels) { @@ -170,6 +171,21 @@ export const setLabelsResolver = authorized< } } + let labelSource: LabelSource | undefined + + // check if source is valid + if (source) { + if (!isLabelSource(source)) { + log.error('invalid source', source) + + return { + errorCodes: [SetLabelsErrorCode.BadRequest], + } + } + + labelSource = source + } + try { let labelsSet: Label[] = [] @@ -191,7 +207,7 @@ export const setLabelsResolver = authorized< } // save labels in the library item - await saveLabelsInLibraryItem(labelsSet, pageId, uid, pubsub) + await saveLabelsInLibraryItem(labelsSet, pageId, uid, labelSource, pubsub) analytics.track({ userId: uid, diff --git a/packages/api/src/routers/svc/following.ts b/packages/api/src/routers/svc/following.ts index 73d8558ac..d2f31d1b6 100644 --- a/packages/api/src/routers/svc/following.ts +++ b/packages/api/src/routers/svc/following.ts @@ -71,9 +71,7 @@ export function followingServiceRouter() { result.identifiers[0].id, userId, [{ name: 'RSS' }], - undefined, - undefined, - true + req.body.addedToFollowingBy ) logger.info('RSS label added to the item') diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index 065e1739b..6c9332167 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -1532,6 +1532,7 @@ const schema = gql` pageId: ID! labelIds: [ID!] labels: [CreateLabelInput!] + source: String } union SetLabelsResult = SetLabelsSuccess | SetLabelsError diff --git a/packages/api/src/services/labels.ts b/packages/api/src/services/labels.ts index cb4c18310..86b9c6297 100644 --- a/packages/api/src/services/labels.ts +++ b/packages/api/src/services/labels.ts @@ -1,6 +1,6 @@ import { DeepPartial, FindOptionsWhere, In } from 'typeorm' import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity' -import { EntityLabel } from '../entity/entity_label' +import { EntityLabel, LabelSource } from '../entity/entity_label' import { Label } from '../entity/label' import { LibraryItem } from '../entity/library_item' import { createPubSubClient, EntityType, PubsubClient } from '../pubsub' @@ -11,6 +11,7 @@ import { libraryItemRepository } from '../repository/library_item' type AddLabelsToLibraryItemEvent = { pageId: string labels: DeepPartial