Add a type for export or import to the integration table
This commit is contained in:
@ -9,6 +9,11 @@ import {
|
||||
} from 'typeorm'
|
||||
import { User } from './user'
|
||||
|
||||
export enum IntegrationType {
|
||||
Export = 'EXPORT',
|
||||
Import = 'IMPORT',
|
||||
}
|
||||
|
||||
@Entity({ name: 'integrations' })
|
||||
export class Integration {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
@ -18,8 +23,14 @@ export class Integration {
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user!: User
|
||||
|
||||
@Column('text')
|
||||
type!: string
|
||||
@Column('varchar', { length: 40 })
|
||||
name!: string
|
||||
|
||||
@Column('enum', {
|
||||
enum: IntegrationType,
|
||||
default: IntegrationType.Export,
|
||||
})
|
||||
type!: IntegrationType
|
||||
|
||||
@Column('varchar', { length: 255 })
|
||||
token!: string
|
||||
|
||||
@ -940,18 +940,37 @@ export enum HighlightType {
|
||||
Redaction = 'REDACTION'
|
||||
}
|
||||
|
||||
export type ImportFromIntegrationError = {
|
||||
__typename?: 'ImportFromIntegrationError';
|
||||
errorCodes: Array<ImportFromIntegrationErrorCode>;
|
||||
};
|
||||
|
||||
export enum ImportFromIntegrationErrorCode {
|
||||
BadRequest = 'BAD_REQUEST',
|
||||
Unauthorized = 'UNAUTHORIZED'
|
||||
}
|
||||
|
||||
export type ImportFromIntegrationResult = ImportFromIntegrationError | ImportFromIntegrationSuccess;
|
||||
|
||||
export type ImportFromIntegrationSuccess = {
|
||||
__typename?: 'ImportFromIntegrationSuccess';
|
||||
success: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type Integration = {
|
||||
__typename?: 'Integration';
|
||||
createdAt: Scalars['Date'];
|
||||
enabled: Scalars['Boolean'];
|
||||
id: Scalars['ID'];
|
||||
name: Scalars['String'];
|
||||
token: Scalars['String'];
|
||||
type: IntegrationType;
|
||||
updatedAt: Scalars['Date'];
|
||||
};
|
||||
|
||||
export enum IntegrationType {
|
||||
Readwise = 'READWISE'
|
||||
Export = 'EXPORT',
|
||||
Import = 'IMPORT'
|
||||
}
|
||||
|
||||
export type IntegrationsError = {
|
||||
@ -1223,6 +1242,7 @@ export type Mutation = {
|
||||
generateApiKey: GenerateApiKeyResult;
|
||||
googleLogin: LoginResult;
|
||||
googleSignup: GoogleSignupResult;
|
||||
importFromIntegration: ImportFromIntegrationResult;
|
||||
joinGroup: JoinGroupResult;
|
||||
leaveGroup: LeaveGroupResult;
|
||||
logOut: LogOutResult;
|
||||
@ -1389,6 +1409,11 @@ export type MutationGoogleSignupArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationImportFromIntegrationArgs = {
|
||||
integrationId: Scalars['ID'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationJoinGroupArgs = {
|
||||
inviteCode: Scalars['String'];
|
||||
};
|
||||
@ -2387,8 +2412,9 @@ export enum SetIntegrationErrorCode {
|
||||
export type SetIntegrationInput = {
|
||||
enabled: Scalars['Boolean'];
|
||||
id?: InputMaybe<Scalars['ID']>;
|
||||
name: Scalars['String'];
|
||||
token: Scalars['String'];
|
||||
type: IntegrationType;
|
||||
type?: InputMaybe<IntegrationType>;
|
||||
};
|
||||
|
||||
export type SetIntegrationResult = SetIntegrationError | SetIntegrationSuccess;
|
||||
@ -3398,6 +3424,10 @@ export type ResolversTypes = {
|
||||
HighlightStats: ResolverTypeWrapper<HighlightStats>;
|
||||
HighlightType: HighlightType;
|
||||
ID: ResolverTypeWrapper<Scalars['ID']>;
|
||||
ImportFromIntegrationError: ResolverTypeWrapper<ImportFromIntegrationError>;
|
||||
ImportFromIntegrationErrorCode: ImportFromIntegrationErrorCode;
|
||||
ImportFromIntegrationResult: ResolversTypes['ImportFromIntegrationError'] | ResolversTypes['ImportFromIntegrationSuccess'];
|
||||
ImportFromIntegrationSuccess: ResolverTypeWrapper<ImportFromIntegrationSuccess>;
|
||||
Int: ResolverTypeWrapper<Scalars['Int']>;
|
||||
Integration: ResolverTypeWrapper<Integration>;
|
||||
IntegrationType: IntegrationType;
|
||||
@ -3842,6 +3872,9 @@ export type ResolversParentTypes = {
|
||||
HighlightReply: HighlightReply;
|
||||
HighlightStats: HighlightStats;
|
||||
ID: Scalars['ID'];
|
||||
ImportFromIntegrationError: ImportFromIntegrationError;
|
||||
ImportFromIntegrationResult: ResolversParentTypes['ImportFromIntegrationError'] | ResolversParentTypes['ImportFromIntegrationSuccess'];
|
||||
ImportFromIntegrationSuccess: ImportFromIntegrationSuccess;
|
||||
Int: Scalars['Int'];
|
||||
Integration: Integration;
|
||||
IntegrationsError: IntegrationsError;
|
||||
@ -4764,10 +4797,25 @@ export type HighlightStatsResolvers<ContextType = ResolverContext, ParentType ex
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type ImportFromIntegrationErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['ImportFromIntegrationError'] = ResolversParentTypes['ImportFromIntegrationError']> = {
|
||||
errorCodes?: Resolver<Array<ResolversTypes['ImportFromIntegrationErrorCode']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type ImportFromIntegrationResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['ImportFromIntegrationResult'] = ResolversParentTypes['ImportFromIntegrationResult']> = {
|
||||
__resolveType: TypeResolveFn<'ImportFromIntegrationError' | 'ImportFromIntegrationSuccess', ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type ImportFromIntegrationSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['ImportFromIntegrationSuccess'] = ResolversParentTypes['ImportFromIntegrationSuccess']> = {
|
||||
success?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type IntegrationResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['Integration'] = ResolversParentTypes['Integration']> = {
|
||||
createdAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
|
||||
enabled?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
|
||||
name?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
token?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
type?: Resolver<ResolversTypes['IntegrationType'], ParentType, ContextType>;
|
||||
updatedAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
|
||||
@ -4975,6 +5023,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
|
||||
generateApiKey?: Resolver<ResolversTypes['GenerateApiKeyResult'], ParentType, ContextType, RequireFields<MutationGenerateApiKeyArgs, 'input'>>;
|
||||
googleLogin?: Resolver<ResolversTypes['LoginResult'], ParentType, ContextType, RequireFields<MutationGoogleLoginArgs, 'input'>>;
|
||||
googleSignup?: Resolver<ResolversTypes['GoogleSignupResult'], ParentType, ContextType, RequireFields<MutationGoogleSignupArgs, 'input'>>;
|
||||
importFromIntegration?: Resolver<ResolversTypes['ImportFromIntegrationResult'], ParentType, ContextType, RequireFields<MutationImportFromIntegrationArgs, 'integrationId'>>;
|
||||
joinGroup?: Resolver<ResolversTypes['JoinGroupResult'], ParentType, ContextType, RequireFields<MutationJoinGroupArgs, 'inviteCode'>>;
|
||||
leaveGroup?: Resolver<ResolversTypes['LeaveGroupResult'], ParentType, ContextType, RequireFields<MutationLeaveGroupArgs, 'groupId'>>;
|
||||
logOut?: Resolver<ResolversTypes['LogOutResult'], ParentType, ContextType>;
|
||||
@ -6086,6 +6135,9 @@ export type Resolvers<ContextType = ResolverContext> = {
|
||||
Highlight?: HighlightResolvers<ContextType>;
|
||||
HighlightReply?: HighlightReplyResolvers<ContextType>;
|
||||
HighlightStats?: HighlightStatsResolvers<ContextType>;
|
||||
ImportFromIntegrationError?: ImportFromIntegrationErrorResolvers<ContextType>;
|
||||
ImportFromIntegrationResult?: ImportFromIntegrationResultResolvers<ContextType>;
|
||||
ImportFromIntegrationSuccess?: ImportFromIntegrationSuccessResolvers<ContextType>;
|
||||
Integration?: IntegrationResolvers<ContextType>;
|
||||
IntegrationsError?: IntegrationsErrorResolvers<ContextType>;
|
||||
IntegrationsResult?: IntegrationsResultResolvers<ContextType>;
|
||||
|
||||
@ -835,17 +835,34 @@ enum HighlightType {
|
||||
REDACTION
|
||||
}
|
||||
|
||||
type ImportFromIntegrationError {
|
||||
errorCodes: [ImportFromIntegrationErrorCode!]!
|
||||
}
|
||||
|
||||
enum ImportFromIntegrationErrorCode {
|
||||
BAD_REQUEST
|
||||
UNAUTHORIZED
|
||||
}
|
||||
|
||||
union ImportFromIntegrationResult = ImportFromIntegrationError | ImportFromIntegrationSuccess
|
||||
|
||||
type ImportFromIntegrationSuccess {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type Integration {
|
||||
createdAt: Date!
|
||||
enabled: Boolean!
|
||||
id: ID!
|
||||
name: String!
|
||||
token: String!
|
||||
type: IntegrationType!
|
||||
updatedAt: Date!
|
||||
}
|
||||
|
||||
enum IntegrationType {
|
||||
READWISE
|
||||
EXPORT
|
||||
IMPORT
|
||||
}
|
||||
|
||||
type IntegrationsError {
|
||||
@ -1093,6 +1110,7 @@ type Mutation {
|
||||
generateApiKey(input: GenerateApiKeyInput!): GenerateApiKeyResult!
|
||||
googleLogin(input: GoogleLoginInput!): LoginResult!
|
||||
googleSignup(input: GoogleSignupInput!): GoogleSignupResult!
|
||||
importFromIntegration(integrationId: ID!): ImportFromIntegrationResult!
|
||||
joinGroup(inviteCode: String!): JoinGroupResult!
|
||||
leaveGroup(groupId: ID!): LeaveGroupResult!
|
||||
logOut: LogOutResult!
|
||||
@ -1775,8 +1793,9 @@ enum SetIntegrationErrorCode {
|
||||
input SetIntegrationInput {
|
||||
enabled: Boolean!
|
||||
id: ID
|
||||
name: String!
|
||||
token: String!
|
||||
type: IntegrationType!
|
||||
type: IntegrationType
|
||||
}
|
||||
|
||||
union SetIntegrationResult = SetIntegrationError | SetIntegrationSuccess
|
||||
|
||||
@ -6,7 +6,6 @@ import {
|
||||
IntegrationsError,
|
||||
IntegrationsErrorCode,
|
||||
IntegrationsSuccess,
|
||||
IntegrationType,
|
||||
MutationDeleteIntegrationArgs,
|
||||
MutationSetIntegrationArgs,
|
||||
SetIntegrationError,
|
||||
@ -65,27 +64,17 @@ export const setIntegrationResolver = authorized<
|
||||
}
|
||||
} else {
|
||||
// Create
|
||||
const existingIntegration = await getRepository(Integration).findOneBy({
|
||||
user: { id: uid },
|
||||
type: input.type,
|
||||
})
|
||||
|
||||
if (existingIntegration) {
|
||||
return {
|
||||
errorCodes: [SetIntegrationErrorCode.AlreadyExists],
|
||||
}
|
||||
}
|
||||
|
||||
// validate token
|
||||
if (!(await validateToken(input.token, input.type))) {
|
||||
if (!(await validateToken(input.token, input.name))) {
|
||||
return {
|
||||
errorCodes: [SetIntegrationErrorCode.InvalidToken],
|
||||
}
|
||||
}
|
||||
integrationToSave = {
|
||||
...integrationToSave,
|
||||
name: input.name,
|
||||
type: input.type ?? undefined,
|
||||
token: input.token,
|
||||
type: input.type,
|
||||
enabled: true,
|
||||
}
|
||||
}
|
||||
@ -126,10 +115,7 @@ export const setIntegrationResolver = authorized<
|
||||
})
|
||||
|
||||
return {
|
||||
integration: {
|
||||
...integration,
|
||||
type: integration.type as IntegrationType,
|
||||
},
|
||||
integration,
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(error)
|
||||
@ -158,10 +144,7 @@ export const integrationsResolver = authorized<
|
||||
})
|
||||
|
||||
return {
|
||||
integrations: integrations.map((integration) => ({
|
||||
...integration,
|
||||
type: integration.type as IntegrationType,
|
||||
})),
|
||||
integrations,
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(error)
|
||||
@ -225,10 +208,7 @@ export const deleteIntegrationResolver = authorized<
|
||||
})
|
||||
|
||||
return {
|
||||
integration: {
|
||||
...deletedIntegration,
|
||||
type: deletedIntegration.type as IntegrationType,
|
||||
},
|
||||
integration,
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(error)
|
||||
|
||||
@ -24,10 +24,10 @@ const logger = buildLogger('app.dispatch')
|
||||
export function integrationsServiceRouter() {
|
||||
const router = express.Router()
|
||||
|
||||
router.post('/:integrationType/:action', async (req, res) => {
|
||||
router.post('/:integrationName/:action', async (req, res) => {
|
||||
logger.info('start to sync with integration', {
|
||||
action: req.params.action,
|
||||
integrationType: req.params.integrationType,
|
||||
integrationName: req.params.integrationName,
|
||||
})
|
||||
const { message: msgStr, expired } = readPushSubscription(req)
|
||||
|
||||
@ -54,7 +54,8 @@ export function integrationsServiceRouter() {
|
||||
|
||||
const integration = await getRepository(Integration).findOneBy({
|
||||
user: { id: userId },
|
||||
type: req.params.integrationType.toUpperCase(),
|
||||
name: req.params.integrationName.toUpperCase(),
|
||||
type: IntegrationType.Export,
|
||||
enabled: true,
|
||||
})
|
||||
if (!integration) {
|
||||
|
||||
@ -1903,6 +1903,7 @@ const schema = gql`
|
||||
|
||||
type Integration {
|
||||
id: ID!
|
||||
name: String!
|
||||
type: IntegrationType!
|
||||
token: String!
|
||||
enabled: Boolean!
|
||||
@ -1911,7 +1912,8 @@ const schema = gql`
|
||||
}
|
||||
|
||||
enum IntegrationType {
|
||||
READWISE
|
||||
EXPORT
|
||||
IMPORT
|
||||
}
|
||||
|
||||
type SetIntegrationError {
|
||||
@ -1928,7 +1930,8 @@ const schema = gql`
|
||||
|
||||
input SetIntegrationInput {
|
||||
id: ID
|
||||
type: IntegrationType!
|
||||
name: String!
|
||||
type: IntegrationType
|
||||
token: String!
|
||||
enabled: Boolean!
|
||||
}
|
||||
@ -2416,6 +2419,23 @@ const schema = gql`
|
||||
UNAUTHORIZED
|
||||
}
|
||||
|
||||
union ImportFromIntegrationResult =
|
||||
ImportFromIntegrationSuccess
|
||||
| ImportFromIntegrationError
|
||||
|
||||
type ImportFromIntegrationSuccess {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type ImportFromIntegrationError {
|
||||
errorCodes: [ImportFromIntegrationErrorCode!]!
|
||||
}
|
||||
|
||||
enum ImportFromIntegrationErrorCode {
|
||||
UNAUTHORIZED
|
||||
BAD_REQUEST
|
||||
}
|
||||
|
||||
# Mutations
|
||||
type Mutation {
|
||||
googleLogin(input: GoogleLoginInput!): LoginResult!
|
||||
@ -2506,6 +2526,7 @@ const schema = gql`
|
||||
): UploadImportFileResult!
|
||||
markEmailAsItem(recentEmailId: ID!): MarkEmailAsItemResult!
|
||||
bulkAction(query: String, action: BulkActionType!): BulkActionResult!
|
||||
importFromIntegration(integrationId: ID!): ImportFromIntegrationResult!
|
||||
}
|
||||
|
||||
# FIXME: remove sort from feedArticles after all cached tabs are closed
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { IntegrationType } from '../generated/graphql'
|
||||
import { env } from '../env'
|
||||
import axios from 'axios'
|
||||
import { wait } from '../utils/helpers'
|
||||
@ -38,10 +37,10 @@ export const READWISE_API_URL = 'https://readwise.io/api/v2'
|
||||
|
||||
export const validateToken = async (
|
||||
token: string,
|
||||
type: IntegrationType
|
||||
name: string
|
||||
): Promise<boolean> => {
|
||||
switch (type) {
|
||||
case IntegrationType.Readwise:
|
||||
switch (name) {
|
||||
case 'READWISE':
|
||||
return validateReadwiseToken(token)
|
||||
default:
|
||||
return false
|
||||
@ -97,8 +96,8 @@ export const syncWithIntegration = async (
|
||||
pages: Page[]
|
||||
): Promise<boolean> => {
|
||||
let result = true
|
||||
switch (integration.type) {
|
||||
case IntegrationType.Readwise: {
|
||||
switch (integration.name) {
|
||||
case 'READWISE': {
|
||||
const highlights = pages.flatMap(pageToReadwiseHighlight)
|
||||
// If there are no highlights, we will skip the sync
|
||||
if (highlights.length > 0) {
|
||||
|
||||
@ -2,10 +2,7 @@ import 'mocha'
|
||||
import { User } from '../../src/entity/user'
|
||||
import { createTestUser, deleteTestIntegrations, deleteTestUser } from '../db'
|
||||
import { generateFakeUuid, graphqlRequest, request } from '../util'
|
||||
import {
|
||||
IntegrationType,
|
||||
SetIntegrationErrorCode,
|
||||
} from '../../src/generated/graphql'
|
||||
import { SetIntegrationErrorCode } from '../../src/generated/graphql'
|
||||
import { expect } from 'chai'
|
||||
import { getRepository } from '../../src/entity/utils'
|
||||
import { Integration } from '../../src/entity/integration'
|
||||
@ -34,14 +31,14 @@ describe('Integrations resolvers', () => {
|
||||
const validToken = 'valid-token'
|
||||
const query = (
|
||||
id = '',
|
||||
type: IntegrationType = IntegrationType.Readwise,
|
||||
name = 'READWISE',
|
||||
token: string = 'test token',
|
||||
enabled = true
|
||||
) => `
|
||||
mutation {
|
||||
setIntegration(input: {
|
||||
id: "${id}",
|
||||
type: ${type},
|
||||
name: ${name},
|
||||
token: "${token}",
|
||||
enabled: ${enabled},
|
||||
}) {
|
||||
@ -59,7 +56,7 @@ describe('Integrations resolvers', () => {
|
||||
`
|
||||
let integrationId: string
|
||||
let token: string
|
||||
let integrationType: IntegrationType
|
||||
let integrationName: string
|
||||
let enabled: boolean
|
||||
let scope: nock.Scope
|
||||
|
||||
@ -88,10 +85,10 @@ describe('Integrations resolvers', () => {
|
||||
before(async () => {
|
||||
existingIntegration = await getRepository(Integration).save({
|
||||
user: { id: loginUser.id },
|
||||
type: 'READWISE',
|
||||
name: 'READWISE',
|
||||
token: 'fakeToken',
|
||||
})
|
||||
integrationType = existingIntegration.type as IntegrationType
|
||||
integrationName = existingIntegration.name
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
@ -100,7 +97,7 @@ describe('Integrations resolvers', () => {
|
||||
|
||||
it('returns AlreadyExists error code', async () => {
|
||||
const res = await graphqlRequest(
|
||||
query(integrationId, integrationType),
|
||||
query(integrationId, integrationName),
|
||||
authToken
|
||||
)
|
||||
expect(res.body.data.setIntegration.errorCodes).to.eql([
|
||||
@ -117,7 +114,7 @@ describe('Integrations resolvers', () => {
|
||||
|
||||
it('returns InvalidToken error code', async () => {
|
||||
const res = await graphqlRequest(
|
||||
query(integrationId, integrationType, token),
|
||||
query(integrationId, integrationName, token),
|
||||
authToken
|
||||
)
|
||||
expect(res.body.data.setIntegration.errorCodes).to.eql([
|
||||
@ -134,13 +131,13 @@ describe('Integrations resolvers', () => {
|
||||
afterEach(async () => {
|
||||
await deleteTestIntegrations(loginUser.id, {
|
||||
user: { id: loginUser.id },
|
||||
type: integrationType,
|
||||
name: integrationName,
|
||||
})
|
||||
})
|
||||
|
||||
it('creates new integration', async () => {
|
||||
const res = await graphqlRequest(
|
||||
query(integrationId, integrationType, token),
|
||||
query(integrationId, integrationName, token),
|
||||
authToken
|
||||
)
|
||||
expect(res.body.data.setIntegration.integration.enabled).to.be.true
|
||||
@ -148,7 +145,7 @@ describe('Integrations resolvers', () => {
|
||||
|
||||
it('creates new cloud task to sync all existing articles and highlights', async () => {
|
||||
const res = await graphqlRequest(
|
||||
query(integrationId, integrationType, token),
|
||||
query(integrationId, integrationName, token),
|
||||
authToken
|
||||
)
|
||||
const integration = await getRepository(Integration).findOneBy({
|
||||
@ -170,7 +167,7 @@ describe('Integrations resolvers', () => {
|
||||
|
||||
it('returns NotFound error code', async () => {
|
||||
const res = await graphqlRequest(
|
||||
query(integrationId, integrationType),
|
||||
query(integrationId, integrationName),
|
||||
authToken
|
||||
)
|
||||
expect(res.body.data.setIntegration.errorCodes).to.eql([
|
||||
@ -187,7 +184,7 @@ describe('Integrations resolvers', () => {
|
||||
otherUser = await createTestUser('otherUser')
|
||||
existingIntegration = await getRepository(Integration).save({
|
||||
user: { id: otherUser.id },
|
||||
type: 'READWISE',
|
||||
name: 'READWISE',
|
||||
token: 'fakeToken',
|
||||
})
|
||||
integrationId = existingIntegration.id
|
||||
@ -200,7 +197,7 @@ describe('Integrations resolvers', () => {
|
||||
|
||||
it('returns Unauthorized error code', async () => {
|
||||
const res = await graphqlRequest(
|
||||
query(integrationId, integrationType),
|
||||
query(integrationId, integrationName),
|
||||
authToken
|
||||
)
|
||||
expect(res.body.data.setIntegration.errorCodes).to.eql([
|
||||
@ -213,7 +210,7 @@ describe('Integrations resolvers', () => {
|
||||
before(async () => {
|
||||
existingIntegration = await getRepository(Integration).save({
|
||||
user: { id: loginUser.id },
|
||||
type: 'READWISE',
|
||||
name: 'READWISE',
|
||||
token: 'fakeToken',
|
||||
})
|
||||
integrationId = existingIntegration.id
|
||||
@ -237,7 +234,7 @@ describe('Integrations resolvers', () => {
|
||||
|
||||
it('disables integration', async () => {
|
||||
const res = await graphqlRequest(
|
||||
query(integrationId, integrationType, token, enabled),
|
||||
query(integrationId, integrationName, token, enabled),
|
||||
authToken
|
||||
)
|
||||
expect(res.body.data.setIntegration.integration.enabled).to.be
|
||||
@ -246,7 +243,7 @@ describe('Integrations resolvers', () => {
|
||||
|
||||
it('deletes cloud task', async () => {
|
||||
const res = await graphqlRequest(
|
||||
query(integrationId, integrationType, token, enabled),
|
||||
query(integrationId, integrationName, token, enabled),
|
||||
authToken
|
||||
)
|
||||
const integration = await getRepository(Integration).findOneBy({
|
||||
@ -270,7 +267,7 @@ describe('Integrations resolvers', () => {
|
||||
|
||||
it('enables integration', async () => {
|
||||
const res = await graphqlRequest(
|
||||
query(integrationId, integrationType, token, enabled),
|
||||
query(integrationId, integrationName, token, enabled),
|
||||
authToken
|
||||
)
|
||||
expect(res.body.data.setIntegration.integration.enabled).to.be
|
||||
@ -279,7 +276,7 @@ describe('Integrations resolvers', () => {
|
||||
|
||||
it('creates new cloud task to sync all existing articles and highlights', async () => {
|
||||
const res = await graphqlRequest(
|
||||
query(integrationId, integrationType, token, enabled),
|
||||
query(integrationId, integrationName, token, enabled),
|
||||
authToken
|
||||
)
|
||||
const integration = await getRepository(Integration).findOneBy({
|
||||
@ -313,7 +310,7 @@ describe('Integrations resolvers', () => {
|
||||
before(async () => {
|
||||
existingIntegration = await getRepository(Integration).save({
|
||||
user: { id: loginUser.id },
|
||||
type: 'READWISE',
|
||||
name: 'READWISE',
|
||||
token: 'fakeToken',
|
||||
})
|
||||
})
|
||||
@ -359,7 +356,7 @@ describe('Integrations resolvers', () => {
|
||||
beforeEach(async () => {
|
||||
existingIntegration = await getRepository(Integration).save({
|
||||
user: { id: loginUser.id },
|
||||
type: 'READWISE',
|
||||
name: 'READWISE',
|
||||
token: 'fakeToken',
|
||||
taskName: 'some task name',
|
||||
})
|
||||
|
||||
@ -26,11 +26,11 @@ describe('Integrations routers', () => {
|
||||
let token: string
|
||||
|
||||
describe('sync with integrations', () => {
|
||||
const endpoint = (token: string, type = 'type', action = 'action') =>
|
||||
`/svc/pubsub/integrations/${type}/${action}?token=${token}`
|
||||
const endpoint = (token: string, name = 'name', action = 'action') =>
|
||||
`/svc/pubsub/integrations/${name}/${action}?token=${token}`
|
||||
let action: string
|
||||
let data: PubSubRequestBody
|
||||
let integrationType: string
|
||||
let integrationName: string
|
||||
|
||||
context('when token is invalid', () => {
|
||||
before(() => {
|
||||
@ -95,7 +95,7 @@ describe('Integrations routers', () => {
|
||||
|
||||
context('when integration not found', () => {
|
||||
before(() => {
|
||||
integrationType = 'READWISE'
|
||||
integrationName = 'READWISE'
|
||||
data = {
|
||||
message: {
|
||||
data: Buffer.from(
|
||||
@ -108,7 +108,7 @@ describe('Integrations routers', () => {
|
||||
|
||||
it('returns 200 with No integration found', async () => {
|
||||
const res = await request
|
||||
.post(endpoint(token, integrationType))
|
||||
.post(endpoint(token, integrationName))
|
||||
.send(data)
|
||||
.expect(200)
|
||||
expect(res.text).to.eql('No integration found')
|
||||
@ -125,10 +125,10 @@ describe('Integrations routers', () => {
|
||||
before(async () => {
|
||||
integration = await getRepository(Integration).save({
|
||||
user: { id: user.id },
|
||||
type: 'READWISE',
|
||||
name: 'READWISE',
|
||||
token: 'token',
|
||||
})
|
||||
integrationType = integration.type
|
||||
integrationName = integration.name
|
||||
// create page
|
||||
page = await createTestElasticPage(user.id)
|
||||
ctx = {
|
||||
@ -177,7 +177,7 @@ describe('Integrations routers', () => {
|
||||
})
|
||||
|
||||
context('when action is sync_updated', () => {
|
||||
before(async () => {
|
||||
before(() => {
|
||||
action = 'sync_updated'
|
||||
})
|
||||
|
||||
@ -208,7 +208,7 @@ describe('Integrations routers', () => {
|
||||
|
||||
it('returns 200 with OK', async () => {
|
||||
const res = await request
|
||||
.post(endpoint(token, integrationType, action))
|
||||
.post(endpoint(token, integrationName, action))
|
||||
.send(data)
|
||||
.expect(200)
|
||||
expect(res.text).to.eql('OK')
|
||||
@ -240,7 +240,7 @@ describe('Integrations routers', () => {
|
||||
|
||||
it('returns 200 with OK', async () => {
|
||||
const res = await request
|
||||
.post(endpoint(token, integrationType, action))
|
||||
.post(endpoint(token, integrationName, action))
|
||||
.send(data)
|
||||
.expect(200)
|
||||
expect(res.text).to.eql('OK')
|
||||
@ -275,7 +275,7 @@ describe('Integrations routers', () => {
|
||||
|
||||
it('returns 200 with OK', async () => {
|
||||
const res = await request
|
||||
.post(endpoint(token, integrationType, action))
|
||||
.post(endpoint(token, integrationName, action))
|
||||
.send(data)
|
||||
.expect(200)
|
||||
expect(res.text).to.eql('OK')
|
||||
@ -313,7 +313,7 @@ describe('Integrations routers', () => {
|
||||
|
||||
it('returns 200 with OK', async () => {
|
||||
const res = await request
|
||||
.post(endpoint(token, integrationType, action))
|
||||
.post(endpoint(token, integrationName, action))
|
||||
.send(data)
|
||||
.expect(200)
|
||||
expect(res.text).to.eql('OK')
|
||||
|
||||
@ -4,6 +4,13 @@
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE omnivore.integrations ALTER COLUMN "type" TYPE text;
|
||||
ALTER TABLE omnivore.integrations RENAME COLUMN "type" TO "name";
|
||||
ALTER TABLE omnivore.integrations
|
||||
DROP CONSTRAINT integrations_user_id_type_key,
|
||||
ALTER COLUMN "name" TYPE VARCHAR(40) USING "name"::VARCHAR(40);
|
||||
DROP TYPE omnivore.integration_type;
|
||||
CREATE TYPE omnivore.integration_type AS ENUM ('EXPORT', 'IMPORT');
|
||||
ALTER TABLE omnivore.integrations
|
||||
ADD COLUMN "type" omnivore.integration_type NOT NULL DEFAULT 'EXPORT';
|
||||
|
||||
COMMIT;
|
||||
|
||||
@ -4,6 +4,12 @@
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE omnivore.integrations ALTER COLUMN "type" TYPE omnivore.integration_type USING "type"::omnivore.integration_type;
|
||||
ALTER TABLE omnivore.integrations DROP COLUMN "type";
|
||||
DROP TYPE omnivore.integration_type;
|
||||
CREATE TYPE omnivore.integration_type AS ENUM ('READWISE', 'POCKET');
|
||||
ALTER TABLE omnivore.integrations
|
||||
ALTER COLUMN "name" TYPE omnivore.integration_type USING "name"::omnivore.integration_type,
|
||||
ADD CONSTRAINT integrations_user_id_type_key UNIQUE (user_id, "name");
|
||||
ALTER TABLE omnivore.integrations RENAME COLUMN "name" TO "type";
|
||||
|
||||
COMMIT;
|
||||
|
||||
Reference in New Issue
Block a user