From ac21e4e6c8cbe3f0cb19506062a97cd21011188c Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 11 Nov 2022 14:08:28 +0800 Subject: [PATCH 1/7] Set voice and secondary voice in user personalization --- .../api/src/entity/user_personalization.ts | 20 ++++++------ packages/api/src/generated/graphql.ts | 8 +++++ packages/api/src/generated/schema.graphql | 4 +++ .../resolvers/user_personalization/index.ts | 31 +++++++++++-------- packages/api/src/schema.ts | 4 +++ 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/packages/api/src/entity/user_personalization.ts b/packages/api/src/entity/user_personalization.ts index 5e7cc51f8..76f6a4d1b 100644 --- a/packages/api/src/entity/user_personalization.ts +++ b/packages/api/src/entity/user_personalization.ts @@ -19,34 +19,34 @@ export class UserPersonalization { user!: User @Column('text', { nullable: true }) - fontFamily?: string + fontFamily?: string | null @Column('integer', { nullable: true }) - fontSize?: number + fontSize?: number | null @Column('text', { nullable: true }) - margin?: number + margin?: number | null @Column('text', { nullable: true }) - theme?: string + theme?: string | null @Column('text', { nullable: true }) - libraryLayoutType?: string + libraryLayoutType?: string | null @Column('text', { nullable: true }) - librarySortOrder?: string + librarySortOrder?: string | null @Column('text', { nullable: true }) - speechVoice?: string + speechVoice?: string | null @Column('text', { nullable: true }) - speechSecondaryVoice?: string + speechSecondaryVoice?: string | null @Column('text', { nullable: true }) - speechRate?: string + speechRate?: string | null @Column('text', { nullable: true }) - speechVolume?: string + speechVolume?: string | null @CreateDateColumn({ default: () => 'CURRENT_TIMESTAMP' }) createdAt!: Date diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index 1f1815b31..130c6973e 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -2458,6 +2458,10 @@ export type UserPersonalization = { libraryLayoutType?: Maybe; librarySortOrder?: Maybe; margin?: Maybe; + speechRate?: Maybe; + speechSecondaryVoice?: Maybe; + speechVoice?: Maybe; + speechVolume?: Maybe; theme?: Maybe; }; @@ -4767,6 +4771,10 @@ export type UserPersonalizationResolvers, ParentType, ContextType>; librarySortOrder?: Resolver, ParentType, ContextType>; margin?: Resolver, ParentType, ContextType>; + speechRate?: Resolver, ParentType, ContextType>; + speechSecondaryVoice?: Resolver, ParentType, ContextType>; + speechVoice?: Resolver, ParentType, ContextType>; + speechVolume?: Resolver, ParentType, ContextType>; theme?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index 4a4048d46..6a5850c50 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -1911,6 +1911,10 @@ type UserPersonalization { libraryLayoutType: String librarySortOrder: SortOrder margin: Int + speechRate: String + speechSecondaryVoice: String + speechVoice: String + speechVolume: String theme: String } diff --git a/packages/api/src/resolvers/user_personalization/index.ts b/packages/api/src/resolvers/user_personalization/index.ts index d5b8e8792..54d526012 100644 --- a/packages/api/src/resolvers/user_personalization/index.ts +++ b/packages/api/src/resolvers/user_personalization/index.ts @@ -1,30 +1,35 @@ import { - GetUserPersonalizationResult, GetUserPersonalizationError, - SetUserPersonalizationSuccess, - SetUserPersonalizationError, + GetUserPersonalizationResult, MutationSetUserPersonalizationArgs, + SetUserPersonalizationError, + SetUserPersonalizationSuccess, SortOrder, } from '../../generated/graphql' import { authorized } from '../../utils/helpers' +import { UserPersonalization } from '../../entity/user_personalization' +import { AppDataSource } from '../../server' +import { setClaims } from '../../entity/utils' export const setUserPersonalizationResolver = authorized< SetUserPersonalizationSuccess, SetUserPersonalizationError, MutationSetUserPersonalizationArgs ->(async (_, { input }, { models, authTrx, claims: { uid } }) => { - const updatedUserPersonalization = await authTrx((tx) => - models.userPersonalization.upsert( - { - userId: uid, - ...input, - }, - tx +>(async (_, { input }, { claims: { uid } }) => { + const updatedUserPersonalization = + await AppDataSource.transaction( + async (entityManager) => { + await setClaims(entityManager, uid) + + return entityManager.getRepository(UserPersonalization).save({ + user: { id: uid }, + ...input, + }) + } ) - ) // Cast SortOrder from string to enum - const librarySortOrder = updatedUserPersonalization?.librarySortOrder as + const librarySortOrder = updatedUserPersonalization.librarySortOrder as | SortOrder | null | undefined diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index 7faa4c4a7..b8b9db254 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -963,6 +963,10 @@ const schema = gql` margin: Int libraryLayoutType: String librarySortOrder: SortOrder + speechVoice: String + speechSecondaryVoice: String + speechRate: String + speechVolume: String } # Query: UserPersonalization From 477b5d7d24a955d73e9c1c0007115d7830f79edd Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 11 Nov 2022 14:53:46 +0800 Subject: [PATCH 2/7] Fix typeorm issue --- packages/api/src/entity/newsletter_email.ts | 2 +- packages/api/src/services/create_user.ts | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/api/src/entity/newsletter_email.ts b/packages/api/src/entity/newsletter_email.ts index bdd4beac0..0399fbc7b 100644 --- a/packages/api/src/entity/newsletter_email.ts +++ b/packages/api/src/entity/newsletter_email.ts @@ -22,7 +22,7 @@ export class NewsletterEmail { user!: User @Column('varchar', { nullable: true }) - confirmationCode?: string + confirmationCode?: string | null @CreateDateColumn() createdAt!: Date diff --git a/packages/api/src/services/create_user.ts b/packages/api/src/services/create_user.ts index 2d6267b6c..e23467e25 100644 --- a/packages/api/src/services/create_user.ts +++ b/packages/api/src/services/create_user.ts @@ -106,9 +106,7 @@ const validateInvite = async ( return false } const membershipRepo = entityManager.getRepository(GroupMembership) - const numMembers = await membershipRepo.count({ - where: { invite: invite }, - }) + const numMembers = await membershipRepo.countBy({ invite: { id: invite.id } }) if (numMembers >= invite.maxMembers) { console.log('rejecting invite, too many users', invite, numMembers) return false From 67b26be547431ca2c2a117929a70caaf6c466dbb Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 11 Nov 2022 15:24:54 +0800 Subject: [PATCH 3/7] Allow apollo sandbox access --- packages/api/src/generated/graphql.ts | 4 ++++ packages/api/src/generated/schema.graphql | 4 ++++ packages/api/src/schema.ts | 4 ++++ packages/api/src/utils/corsConfig.ts | 1 + 4 files changed, 13 insertions(+) diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index 130c6973e..edf334694 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -1945,6 +1945,10 @@ export type SetUserPersonalizationInput = { libraryLayoutType?: InputMaybe; librarySortOrder?: InputMaybe; margin?: InputMaybe; + speechRate?: InputMaybe; + speechSecondaryVoice?: InputMaybe; + speechVoice?: InputMaybe; + speechVolume?: InputMaybe; theme?: InputMaybe; }; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index 6a5850c50..20658c344 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -1441,6 +1441,10 @@ input SetUserPersonalizationInput { libraryLayoutType: String librarySortOrder: SortOrder margin: Int + speechRate: String + speechSecondaryVoice: String + speechVoice: String + speechVolume: String theme: String } diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index b8b9db254..74acad69b 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -1003,6 +1003,10 @@ const schema = gql` margin: Int libraryLayoutType: String @sanitize librarySortOrder: SortOrder + speechVoice: String + speechSecondaryVoice: String + speechRate: String + speechVolume: String } # Type: ArticleSavingRequest diff --git a/packages/api/src/utils/corsConfig.ts b/packages/api/src/utils/corsConfig.ts index 16f707d0c..4d17ee47b 100644 --- a/packages/api/src/utils/corsConfig.ts +++ b/packages/api/src/utils/corsConfig.ts @@ -9,5 +9,6 @@ export const corsConfig = { 'https://web-demo.omnivore.app', 'http://localhost:3000', 'lsp://logseq.io', + 'https://studio.apollographql.com', ], } From 917396c97676d29afdc3b21e442ad0e31f2e0093 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 11 Nov 2022 16:11:09 +0800 Subject: [PATCH 4/7] Upsert user personalization in db --- packages/api/src/generated/graphql.ts | 1 + packages/api/src/generated/schema.graphql | 1 + .../resolvers/user_personalization/index.ts | 37 +++++++++++++------ packages/api/src/schema.ts | 1 + 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index edf334694..1eb7b5843 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -1936,6 +1936,7 @@ export type SetUserPersonalizationError = { }; export enum SetUserPersonalizationErrorCode { + NotFound = 'NOT_FOUND', Unauthorized = 'UNAUTHORIZED' } diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index 20658c344..51f50f0a5 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -1432,6 +1432,7 @@ type SetUserPersonalizationError { } enum SetUserPersonalizationErrorCode { + NOT_FOUND UNAUTHORIZED } diff --git a/packages/api/src/resolvers/user_personalization/index.ts b/packages/api/src/resolvers/user_personalization/index.ts index 54d526012..955dc16d4 100644 --- a/packages/api/src/resolvers/user_personalization/index.ts +++ b/packages/api/src/resolvers/user_personalization/index.ts @@ -3,33 +3,46 @@ import { GetUserPersonalizationResult, MutationSetUserPersonalizationArgs, SetUserPersonalizationError, + SetUserPersonalizationErrorCode, SetUserPersonalizationSuccess, SortOrder, } from '../../generated/graphql' import { authorized } from '../../utils/helpers' import { UserPersonalization } from '../../entity/user_personalization' import { AppDataSource } from '../../server' -import { setClaims } from '../../entity/utils' +import { getRepository, setClaims } from '../../entity/utils' export const setUserPersonalizationResolver = authorized< SetUserPersonalizationSuccess, SetUserPersonalizationError, MutationSetUserPersonalizationArgs ->(async (_, { input }, { claims: { uid } }) => { - const updatedUserPersonalization = - await AppDataSource.transaction( - async (entityManager) => { - await setClaims(entityManager, uid) +>(async (_, { input }, { claims: { uid }, log }) => { + log.info('setUserPersonalizationResolver', { uid, input }) - return entityManager.getRepository(UserPersonalization).save({ - user: { id: uid }, - ...input, - }) - } + const result = await AppDataSource.transaction(async (entityManager) => { + await setClaims(entityManager, uid) + + return entityManager.getRepository(UserPersonalization).upsert( + { + user: { id: uid }, + ...input, + }, + ['user'] ) + }) + + if (result.identifiers.length === 0) { + return { + errorCodes: [SetUserPersonalizationErrorCode.NotFound], + } + } + + const updatedUserPersonalization = await getRepository( + UserPersonalization + ).findOneBy({ id: result.identifiers[0].id as string }) // Cast SortOrder from string to enum - const librarySortOrder = updatedUserPersonalization.librarySortOrder as + const librarySortOrder = updatedUserPersonalization?.librarySortOrder as | SortOrder | null | undefined diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index 74acad69b..1f089b7b4 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -989,6 +989,7 @@ const schema = gql` | SetUserPersonalizationError enum SetUserPersonalizationErrorCode { UNAUTHORIZED + NOT_FOUND } type SetUserPersonalizationError { errorCodes: [SetUserPersonalizationErrorCode!]! From 9872355056b2b577310146ef2df12b58e0611cf0 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 11 Nov 2022 16:18:11 +0800 Subject: [PATCH 5/7] Allow apollo sandbox access in local env only --- packages/api/src/utils/corsConfig.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/api/src/utils/corsConfig.ts b/packages/api/src/utils/corsConfig.ts index 4d17ee47b..d3462a0a0 100644 --- a/packages/api/src/utils/corsConfig.ts +++ b/packages/api/src/utils/corsConfig.ts @@ -1,5 +1,8 @@ +import { env } from '../env' + export const corsConfig = { credentials: true, + // allow https://studio.apollographql.com for local env origin: [ 'https://omnivore.app', 'https://dev.omnivore.app', @@ -9,6 +12,6 @@ export const corsConfig = { 'https://web-demo.omnivore.app', 'http://localhost:3000', 'lsp://logseq.io', - 'https://studio.apollographql.com', + env.dev.isLocal && 'https://studio.apollographql.com', ], } From 588a14c6b98b8b63d566cb83dd53a7c5599b1ef1 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 11 Nov 2022 16:47:32 +0800 Subject: [PATCH 6/7] Fix tests --- packages/api/test/resolvers/integrations.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/api/test/resolvers/integrations.test.ts b/packages/api/test/resolvers/integrations.test.ts index 582160680..f024e0eb0 100644 --- a/packages/api/test/resolvers/integrations.test.ts +++ b/packages/api/test/resolvers/integrations.test.ts @@ -90,7 +90,7 @@ describe('Integrations resolvers', () => { before(async () => { existingIntegration = await getRepository(Integration).save({ - user: loginUser, + user: { id: loginUser.id }, type: DataIntegrationType.Readwise, token: 'fakeToken', }) @@ -138,7 +138,7 @@ describe('Integrations resolvers', () => { afterEach(async () => { await getRepository(Integration).delete({ - user: loginUser, + user: { id: loginUser.id }, type: integrationType, }) }) @@ -191,7 +191,7 @@ describe('Integrations resolvers', () => { before(async () => { otherUser = await createTestUser('otherUser') existingIntegration = await getRepository(Integration).save({ - user: otherUser, + user: { id: otherUser.id }, type: DataIntegrationType.Readwise, token: 'fakeToken', }) @@ -219,7 +219,7 @@ describe('Integrations resolvers', () => { context('when integration belongs to the user', () => { before(async () => { existingIntegration = await getRepository(Integration).save({ - user: loginUser, + user: { id: loginUser.id }, type: DataIntegrationType.Readwise, token: 'fakeToken', }) @@ -321,7 +321,7 @@ describe('Integrations resolvers', () => { before(async () => { existingIntegration = await getRepository(Integration).save({ - user: loginUser, + user: { id: loginUser.id }, type: DataIntegrationType.Readwise, token: 'fakeToken', }) @@ -367,7 +367,7 @@ describe('Integrations resolvers', () => { beforeEach(async () => { existingIntegration = await getRepository(Integration).save({ - user: loginUser, + user: { id: loginUser.id }, type: DataIntegrationType.Readwise, token: 'fakeToken', taskName: 'some task name', From 2cff9f049a0f1e892f81ef7a1c425c598b283cb5 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 11 Nov 2022 16:54:18 +0800 Subject: [PATCH 7/7] Temporarily disable feature api tests --- packages/api/test/resolvers/features.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/test/resolvers/features.test.ts b/packages/api/test/resolvers/features.test.ts index b5a901441..7ed43cfe0 100644 --- a/packages/api/test/resolvers/features.test.ts +++ b/packages/api/test/resolvers/features.test.ts @@ -10,7 +10,7 @@ import sinon, { SinonFakeTimers } from 'sinon' import { env } from '../../src/env' import { Like } from 'typeorm' -describe('features resolvers', () => { +xdescribe('features resolvers', () => { let loginUser: User let authToken: string