diff --git a/packages/api/package.json b/packages/api/package.json index 258ae3310..a52f999aa 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -46,6 +46,7 @@ "cookie-parser": "^1.4.5", "cors": "^2.8.5", "dataloader": "^2.0.0", + "diff-match-patch": "^1.0.5", "dompurify": "^2.0.17", "dot-case": "^3.0.4", "dotenv": "^8.2.0", @@ -96,6 +97,7 @@ "@types/chai-string": "^1.4.2", "@types/cookie": "^0.4.0", "@types/cookie-parser": "^1.4.2", + "@types/diff-match-patch": "^1.0.32", "@types/dompurify": "^2.0.4", "@types/express": "^4.17.7", "@types/graphql-fields": "^1.3.4", diff --git a/packages/api/src/datalayer/pubsub.ts b/packages/api/src/datalayer/pubsub.ts index e4f397acd..af8522682 100644 --- a/packages/api/src/datalayer/pubsub.ts +++ b/packages/api/src/datalayer/pubsub.ts @@ -111,7 +111,7 @@ interface PubSubRequestMessage { publishTime: string } -interface PubSubRequestBody { +export interface PubSubRequestBody { message: PubSubRequestMessage } diff --git a/packages/api/src/elastic/pages.ts b/packages/api/src/elastic/pages.ts index 9abffd52e..b8c6230f3 100644 --- a/packages/api/src/elastic/pages.ts +++ b/packages/api/src/elastic/pages.ts @@ -274,7 +274,7 @@ export const deletePage = async ( } export const getPageByParam = async ( - param: Record, + param: Record, includeOriginalHtml = false ): Promise => { try { @@ -506,7 +506,7 @@ export const countByCreatedAt = async ( } export const deletePagesByParam = async ( - param: Record, + param: Record, ctx: PageContext ): Promise => { try { diff --git a/packages/api/src/entity/integration.ts b/packages/api/src/entity/integration.ts new file mode 100644 index 000000000..0d1895f64 --- /dev/null +++ b/packages/api/src/entity/integration.ts @@ -0,0 +1,45 @@ +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm' +import { User } from './user' + +export enum IntegrationType { + Readwise = 'READWISE', +} + +@Entity({ name: 'integrations' }) +export class Integration { + @PrimaryGeneratedColumn('uuid') + id!: string + + @ManyToOne(() => User, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'user_id' }) + user!: User + + @Column('enum', { enum: IntegrationType }) + type!: IntegrationType + + @Column('varchar', { length: 255 }) + token!: string + + @Column('boolean', { default: true }) + enabled!: boolean + + @CreateDateColumn({ default: () => 'CURRENT_TIMESTAMP' }) + createdAt!: Date + + @UpdateDateColumn({ default: () => 'CURRENT_TIMESTAMP' }) + updatedAt!: Date + + @Column('timestamp', { nullable: true }) + syncedAt?: Date | null + + @Column('text', { nullable: true }) + taskName?: string | null +} diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index 1ce355cbd..600243e98 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -479,6 +479,24 @@ export type DeleteHighlightSuccess = { highlight: Highlight; }; +export type DeleteIntegrationError = { + __typename?: 'DeleteIntegrationError'; + errorCodes: Array; +}; + +export enum DeleteIntegrationErrorCode { + BadRequest = 'BAD_REQUEST', + NotFound = 'NOT_FOUND', + Unauthorized = 'UNAUTHORIZED' +} + +export type DeleteIntegrationResult = DeleteIntegrationError | DeleteIntegrationSuccess; + +export type DeleteIntegrationSuccess = { + __typename?: 'DeleteIntegrationSuccess'; + integration: Integration; +}; + export type DeleteLabelError = { __typename?: 'DeleteLabelError'; errorCodes: Array; @@ -745,6 +763,37 @@ export type HighlightStats = { highlightCount: Scalars['Int']; }; +export type Integration = { + __typename?: 'Integration'; + createdAt: Scalars['Date']; + enabled: Scalars['Boolean']; + id: Scalars['ID']; + token: Scalars['String']; + type: IntegrationType; + updatedAt: Scalars['Date']; +}; + +export enum IntegrationType { + Readwise = 'READWISE' +} + +export type IntegrationsError = { + __typename?: 'IntegrationsError'; + errorCodes: Array; +}; + +export enum IntegrationsErrorCode { + BadRequest = 'BAD_REQUEST', + Unauthorized = 'UNAUTHORIZED' +} + +export type IntegrationsResult = IntegrationsError | IntegrationsSuccess; + +export type IntegrationsSuccess = { + __typename?: 'IntegrationsSuccess'; + integrations: Array; +}; + export type Label = { __typename?: 'Label'; color: Scalars['String']; @@ -904,6 +953,7 @@ export type Mutation = { deleteAccount: DeleteAccountResult; deleteHighlight: DeleteHighlightResult; deleteHighlightReply: DeleteHighlightReplyResult; + deleteIntegration: DeleteIntegrationResult; deleteLabel: DeleteLabelResult; deleteNewsletterEmail: DeleteNewsletterEmailResult; deleteReaction: DeleteReactionResult; @@ -924,6 +974,7 @@ export type Mutation = { setBookmarkArticle: SetBookmarkArticleResult; setDeviceToken: SetDeviceTokenResult; setFollow: SetFollowResult; + setIntegration: SetIntegrationResult; setLabels: SetLabelsResult; setLabelsForHighlight: SetLabelsResult; setLinkArchived: ArchiveLinkResult; @@ -1001,6 +1052,11 @@ export type MutationDeleteHighlightReplyArgs = { }; +export type MutationDeleteIntegrationArgs = { + id: Scalars['ID']; +}; + + export type MutationDeleteLabelArgs = { id: Scalars['ID']; }; @@ -1096,6 +1152,11 @@ export type MutationSetFollowArgs = { }; +export type MutationSetIntegrationArgs = { + input: SetIntegrationInput; +}; + + export type MutationSetLabelsArgs = { input: SetLabelsInput; }; @@ -1286,6 +1347,7 @@ export type Query = { getFollowing: GetFollowingResult; getUserPersonalization: GetUserPersonalizationResult; hello?: Maybe; + integrations: IntegrationsResult; labels: LabelsResult; me?: Maybe; newsletterEmails: NewsletterEmailsResult; @@ -1694,6 +1756,33 @@ export type SetFollowSuccess = { updatedUser: User; }; +export type SetIntegrationError = { + __typename?: 'SetIntegrationError'; + errorCodes: Array; +}; + +export enum SetIntegrationErrorCode { + AlreadyExists = 'ALREADY_EXISTS', + BadRequest = 'BAD_REQUEST', + InvalidToken = 'INVALID_TOKEN', + NotFound = 'NOT_FOUND', + Unauthorized = 'UNAUTHORIZED' +} + +export type SetIntegrationInput = { + enabled: Scalars['Boolean']; + id?: InputMaybe; + token: Scalars['String']; + type: IntegrationType; +}; + +export type SetIntegrationResult = SetIntegrationError | SetIntegrationSuccess; + +export type SetIntegrationSuccess = { + __typename?: 'SetIntegrationSuccess'; + integration: Integration; +}; + export type SetLabelsError = { __typename?: 'SetLabelsError'; errorCodes: Array; @@ -2537,6 +2626,10 @@ export type ResolversTypes = { DeleteHighlightReplySuccess: ResolverTypeWrapper; DeleteHighlightResult: ResolversTypes['DeleteHighlightError'] | ResolversTypes['DeleteHighlightSuccess']; DeleteHighlightSuccess: ResolverTypeWrapper; + DeleteIntegrationError: ResolverTypeWrapper; + DeleteIntegrationErrorCode: DeleteIntegrationErrorCode; + DeleteIntegrationResult: ResolversTypes['DeleteIntegrationError'] | ResolversTypes['DeleteIntegrationSuccess']; + DeleteIntegrationSuccess: ResolverTypeWrapper; DeleteLabelError: ResolverTypeWrapper; DeleteLabelErrorCode: DeleteLabelErrorCode; DeleteLabelResult: ResolversTypes['DeleteLabelError'] | ResolversTypes['DeleteLabelSuccess']; @@ -2592,6 +2685,12 @@ export type ResolversTypes = { HighlightStats: ResolverTypeWrapper; ID: ResolverTypeWrapper; Int: ResolverTypeWrapper; + Integration: ResolverTypeWrapper; + IntegrationType: IntegrationType; + IntegrationsError: ResolverTypeWrapper; + IntegrationsErrorCode: IntegrationsErrorCode; + IntegrationsResult: ResolversTypes['IntegrationsError'] | ResolversTypes['IntegrationsSuccess']; + IntegrationsSuccess: ResolverTypeWrapper; Label: ResolverTypeWrapper