add export to integration and get task api

This commit is contained in:
Hongbo Wu 2024-03-21 11:14:23 +08:00
parent 79c8d8ebbb
commit 390d12eea1
10 changed files with 318 additions and 91 deletions

View file

@ -892,6 +892,23 @@ export type EmptyTrashSuccess = {
success?: Maybe<Scalars['Boolean']>;
};
export type ExportToIntegrationError = {
__typename?: 'ExportToIntegrationError';
errorCodes: Array<ExportToIntegrationErrorCode>;
};
export enum ExportToIntegrationErrorCode {
FailedToCreateTask = 'FAILED_TO_CREATE_TASK',
Unauthorized = 'UNAUTHORIZED'
}
export type ExportToIntegrationResult = ExportToIntegrationError | ExportToIntegrationSuccess;
export type ExportToIntegrationSuccess = {
__typename?: 'ExportToIntegrationSuccess';
task: Task;
};
export type Feature = {
__typename?: 'Feature';
createdAt: Scalars['Date'];
@ -1582,6 +1599,7 @@ export type Mutation = {
deleteWebhook: DeleteWebhookResult;
editDiscoverFeed: EditDiscoverFeedResult;
emptyTrash: EmptyTrashResult;
exportToIntegration: ExportToIntegrationResult;
fetchContent: FetchContentResult;
generateApiKey: GenerateApiKeyResult;
googleLogin: LoginResult;
@ -1737,6 +1755,11 @@ export type MutationEditDiscoverFeedArgs = {
};
export type MutationExportToIntegrationArgs = {
integrationId: Scalars['ID'];
};
export type MutationFetchContentArgs = {
id: Scalars['ID'];
};
@ -3183,6 +3206,26 @@ export type SyncUpdatedItemEdge = {
updateReason: UpdateReason;
};
export type Task = {
__typename?: 'Task';
cancellable?: Maybe<Scalars['Boolean']>;
createdAt: Scalars['Date'];
failedReason?: Maybe<Scalars['String']>;
id: Scalars['ID'];
name: Scalars['String'];
progress?: Maybe<Scalars['Float']>;
runningTime?: Maybe<Scalars['Int']>;
state: TaskState;
};
export enum TaskState {
Cancelled = 'CANCELLED',
Failed = 'FAILED',
Pending = 'PENDING',
Running = 'RUNNING',
Succeeded = 'SUCCEEDED'
}
export type TypeaheadSearchError = {
__typename?: 'TypeaheadSearchError';
errorCodes: Array<TypeaheadSearchErrorCode>;
@ -4014,6 +4057,10 @@ export type ResolversTypes = {
EmptyTrashErrorCode: EmptyTrashErrorCode;
EmptyTrashResult: ResolversTypes['EmptyTrashError'] | ResolversTypes['EmptyTrashSuccess'];
EmptyTrashSuccess: ResolverTypeWrapper<EmptyTrashSuccess>;
ExportToIntegrationError: ResolverTypeWrapper<ExportToIntegrationError>;
ExportToIntegrationErrorCode: ExportToIntegrationErrorCode;
ExportToIntegrationResult: ResolversTypes['ExportToIntegrationError'] | ResolversTypes['ExportToIntegrationSuccess'];
ExportToIntegrationSuccess: ResolverTypeWrapper<ExportToIntegrationSuccess>;
Feature: ResolverTypeWrapper<Feature>;
Feed: ResolverTypeWrapper<Feed>;
FeedArticle: ResolverTypeWrapper<FeedArticle>;
@ -4323,6 +4370,8 @@ export type ResolversTypes = {
SubscriptionsResult: ResolversTypes['SubscriptionsError'] | ResolversTypes['SubscriptionsSuccess'];
SubscriptionsSuccess: ResolverTypeWrapper<SubscriptionsSuccess>;
SyncUpdatedItemEdge: ResolverTypeWrapper<SyncUpdatedItemEdge>;
Task: ResolverTypeWrapper<Task>;
TaskState: TaskState;
TypeaheadSearchError: ResolverTypeWrapper<TypeaheadSearchError>;
TypeaheadSearchErrorCode: TypeaheadSearchErrorCode;
TypeaheadSearchItem: ResolverTypeWrapper<TypeaheadSearchItem>;
@ -4564,6 +4613,9 @@ export type ResolversParentTypes = {
EmptyTrashError: EmptyTrashError;
EmptyTrashResult: ResolversParentTypes['EmptyTrashError'] | ResolversParentTypes['EmptyTrashSuccess'];
EmptyTrashSuccess: EmptyTrashSuccess;
ExportToIntegrationError: ExportToIntegrationError;
ExportToIntegrationResult: ResolversParentTypes['ExportToIntegrationError'] | ResolversParentTypes['ExportToIntegrationSuccess'];
ExportToIntegrationSuccess: ExportToIntegrationSuccess;
Feature: Feature;
Feed: Feed;
FeedArticle: FeedArticle;
@ -4804,6 +4856,7 @@ export type ResolversParentTypes = {
SubscriptionsResult: ResolversParentTypes['SubscriptionsError'] | ResolversParentTypes['SubscriptionsSuccess'];
SubscriptionsSuccess: SubscriptionsSuccess;
SyncUpdatedItemEdge: SyncUpdatedItemEdge;
Task: Task;
TypeaheadSearchError: TypeaheadSearchError;
TypeaheadSearchItem: TypeaheadSearchItem;
TypeaheadSearchResult: ResolversParentTypes['TypeaheadSearchError'] | ResolversParentTypes['TypeaheadSearchSuccess'];
@ -5502,6 +5555,20 @@ export type EmptyTrashSuccessResolvers<ContextType = ResolverContext, ParentType
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type ExportToIntegrationErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['ExportToIntegrationError'] = ResolversParentTypes['ExportToIntegrationError']> = {
errorCodes?: Resolver<Array<ResolversTypes['ExportToIntegrationErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type ExportToIntegrationResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['ExportToIntegrationResult'] = ResolversParentTypes['ExportToIntegrationResult']> = {
__resolveType: TypeResolveFn<'ExportToIntegrationError' | 'ExportToIntegrationSuccess', ParentType, ContextType>;
};
export type ExportToIntegrationSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['ExportToIntegrationSuccess'] = ResolversParentTypes['ExportToIntegrationSuccess']> = {
task?: Resolver<ResolversTypes['Task'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type FeatureResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['Feature'] = ResolversParentTypes['Feature']> = {
createdAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
expiresAt?: Resolver<Maybe<ResolversTypes['Date']>, ParentType, ContextType>;
@ -6037,6 +6104,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
deleteWebhook?: Resolver<ResolversTypes['DeleteWebhookResult'], ParentType, ContextType, RequireFields<MutationDeleteWebhookArgs, 'id'>>;
editDiscoverFeed?: Resolver<ResolversTypes['EditDiscoverFeedResult'], ParentType, ContextType, RequireFields<MutationEditDiscoverFeedArgs, 'input'>>;
emptyTrash?: Resolver<ResolversTypes['EmptyTrashResult'], ParentType, ContextType>;
exportToIntegration?: Resolver<ResolversTypes['ExportToIntegrationResult'], ParentType, ContextType, RequireFields<MutationExportToIntegrationArgs, 'integrationId'>>;
fetchContent?: Resolver<ResolversTypes['FetchContentResult'], ParentType, ContextType, RequireFields<MutationFetchContentArgs, 'id'>>;
generateApiKey?: Resolver<ResolversTypes['GenerateApiKeyResult'], ParentType, ContextType, RequireFields<MutationGenerateApiKeyArgs, 'input'>>;
googleLogin?: Resolver<ResolversTypes['LoginResult'], ParentType, ContextType, RequireFields<MutationGoogleLoginArgs, 'input'>>;
@ -6788,6 +6856,18 @@ export type SyncUpdatedItemEdgeResolvers<ContextType = ResolverContext, ParentTy
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type TaskResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['Task'] = ResolversParentTypes['Task']> = {
cancellable?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
createdAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
failedReason?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
name?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
progress?: Resolver<Maybe<ResolversTypes['Float']>, ParentType, ContextType>;
runningTime?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
state?: Resolver<ResolversTypes['TaskState'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type TypeaheadSearchErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['TypeaheadSearchError'] = ResolversParentTypes['TypeaheadSearchError']> = {
errorCodes?: Resolver<Array<ResolversTypes['TypeaheadSearchErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
@ -7272,6 +7352,9 @@ export type Resolvers<ContextType = ResolverContext> = {
EmptyTrashError?: EmptyTrashErrorResolvers<ContextType>;
EmptyTrashResult?: EmptyTrashResultResolvers<ContextType>;
EmptyTrashSuccess?: EmptyTrashSuccessResolvers<ContextType>;
ExportToIntegrationError?: ExportToIntegrationErrorResolvers<ContextType>;
ExportToIntegrationResult?: ExportToIntegrationResultResolvers<ContextType>;
ExportToIntegrationSuccess?: ExportToIntegrationSuccessResolvers<ContextType>;
Feature?: FeatureResolvers<ContextType>;
Feed?: FeedResolvers<ContextType>;
FeedArticle?: FeedArticleResolvers<ContextType>;
@ -7473,6 +7556,7 @@ export type Resolvers<ContextType = ResolverContext> = {
SubscriptionsResult?: SubscriptionsResultResolvers<ContextType>;
SubscriptionsSuccess?: SubscriptionsSuccessResolvers<ContextType>;
SyncUpdatedItemEdge?: SyncUpdatedItemEdgeResolvers<ContextType>;
Task?: TaskResolvers<ContextType>;
TypeaheadSearchError?: TypeaheadSearchErrorResolvers<ContextType>;
TypeaheadSearchItem?: TypeaheadSearchItemResolvers<ContextType>;
TypeaheadSearchResult?: TypeaheadSearchResultResolvers<ContextType>;

View file

@ -794,6 +794,21 @@ type EmptyTrashSuccess {
success: Boolean
}
type ExportToIntegrationError {
errorCodes: [ExportToIntegrationErrorCode!]!
}
enum ExportToIntegrationErrorCode {
FAILED_TO_CREATE_TASK
UNAUTHORIZED
}
union ExportToIntegrationResult = ExportToIntegrationError | ExportToIntegrationSuccess
type ExportToIntegrationSuccess {
task: Task!
}
type Feature {
createdAt: Date!
expiresAt: Date
@ -1422,6 +1437,7 @@ type Mutation {
deleteWebhook(id: ID!): DeleteWebhookResult!
editDiscoverFeed(input: EditDiscoverFeedInput!): EditDiscoverFeedResult!
emptyTrash: EmptyTrashResult!
exportToIntegration(integrationId: ID!): ExportToIntegrationResult!
fetchContent(id: ID!): FetchContentResult!
generateApiKey(input: GenerateApiKeyInput!): GenerateApiKeyResult!
googleLogin(input: GoogleLoginInput!): LoginResult!
@ -2517,6 +2533,25 @@ type SyncUpdatedItemEdge {
updateReason: UpdateReason!
}
type Task {
cancellable: Boolean
createdAt: Date!
failedReason: String
id: ID!
name: String!
progress: Float
runningTime: Int
state: TaskState!
}
enum TaskState {
CANCELLED
FAILED
PENDING
RUNNING
SUCCEEDED
}
type TypeaheadSearchError {
errorCodes: [TypeaheadSearchErrorCode!]!
}

View file

@ -5,6 +5,7 @@
import {
ConnectionOptions,
Job,
JobState,
JobType,
Queue,
QueueEvents,
@ -13,6 +14,7 @@ import {
import express, { Express } from 'express'
import { appDataSource } from './data_source'
import { env } from './env'
import { TaskState } from './generated/graphql'
import { aiSummarize, AI_SUMMARIZE_JOB_NAME } from './jobs/ai-summarize'
import { bulkAction, BULK_ACTION_JOB_NAME } from './jobs/bulk_action'
import { callWebhook, CALL_WEBHOOK_JOB_NAME } from './jobs/call_webhook'
@ -25,6 +27,12 @@ import {
exportItem,
EXPORT_ITEM_JOB_NAME,
} from './jobs/integration/export_item'
import {
processYouTubeTranscript,
processYouTubeVideo,
PROCESS_YOUTUBE_TRANSCRIPT_JOB_NAME,
PROCESS_YOUTUBE_VIDEO_JOB_NAME,
} from './jobs/process-youtube-video'
import { refreshAllFeeds } from './jobs/rss/refreshAllFeeds'
import { refreshFeed } from './jobs/rss/refreshFeed'
import { savePageJob } from './jobs/save_page'
@ -44,12 +52,6 @@ import { redisDataSource } from './redis_data_source'
import { CACHED_READING_POSITION_PREFIX } from './services/cached_reading_position'
import { getJobPriority } from './utils/createTask'
import { logger } from './utils/logger'
import {
PROCESS_YOUTUBE_TRANSCRIPT_JOB_NAME,
PROCESS_YOUTUBE_VIDEO_JOB_NAME,
processYouTubeTranscript,
processYouTubeVideo,
} from './jobs/process-youtube-video'
export const QUEUE_NAME = 'omnivore-backend-queue'
export const JOB_VERSION = 'v001'
@ -82,6 +84,33 @@ export const getBackendQueue = async (): Promise<Queue | undefined> => {
return backendQueue
}
export const getJob = async (jobId: string) => {
const queue = await getBackendQueue()
if (!queue) {
return
}
return queue.getJob(jobId)
}
export const jobStateToTaskState = (
jobState: JobState | 'unknown'
): TaskState => {
switch (jobState) {
case 'completed':
return TaskState.Succeeded
case 'failed':
return TaskState.Failed
case 'active':
return TaskState.Running
case 'delayed':
return TaskState.Pending
case 'waiting':
return TaskState.Pending
default:
return TaskState.Pending
}
}
export const createWorker = (connection: ConnectionOptions) =>
new Worker(
QUEUE_NAME,

View file

@ -41,6 +41,15 @@ import {
generateUploadFilePathName,
} from '../utils/uploads'
import { emptyTrashResolver, fetchContentResolver } from './article'
import {
addDiscoverFeedResolver,
deleteDiscoverArticleResolver,
deleteDiscoverFeedsResolver,
editDiscoverFeedsResolver,
getDiscoverFeedArticlesResolver,
getDiscoverFeedsResolver,
saveDiscoverArticleResolver,
} from './discover_feeds'
import { optInFeatureResolver } from './features'
import { uploadImportFileResolver } from './importers/uploadImportFileResolver'
import {
@ -65,6 +74,7 @@ import {
deleteRuleResolver,
deleteWebhookResolver,
deviceTokensResolver,
exportToIntegrationResolver,
feedsResolver,
filtersResolver,
generateApiKeyResolver,
@ -144,15 +154,6 @@ import { markEmailAsItemResolver, recentEmailsResolver } from './recent_emails'
import { recentSearchesResolver } from './recent_searches'
import { WithDataSourcesContext } from './types'
import { updateEmailResolver } from './user'
import {
addDiscoverFeedResolver,
getDiscoverFeedsResolver,
getDiscoverFeedArticlesResolver,
saveDiscoverArticleResolver,
deleteDiscoverArticleResolver,
deleteDiscoverFeedsResolver,
editDiscoverFeedsResolver,
} from './discover_feeds'
/* eslint-disable @typescript-eslint/naming-convention */
type ResultResolveType = {
@ -314,6 +315,7 @@ export const functionResolvers = {
editDiscoverFeed: editDiscoverFeedsResolver,
emptyTrash: emptyTrashResolver,
fetchContent: fetchContentResolver,
exportToIntegration: exportToIntegrationResolver,
},
Query: {
me: getMeUserResolver,
@ -665,4 +667,5 @@ export const functionResolvers = {
...resultResolveTypeResolver('EmptyTrash'),
...resultResolveTypeResolver('FetchContent'),
...resultResolveTypeResolver('Integration'),
...resultResolveTypeResolver('ExportToIntegration'),
}

View file

@ -9,6 +9,9 @@ import {
DeleteIntegrationError,
DeleteIntegrationErrorCode,
DeleteIntegrationSuccess,
ExportToIntegrationError,
ExportToIntegrationErrorCode,
ExportToIntegrationSuccess,
ImportFromIntegrationError,
ImportFromIntegrationErrorCode,
ImportFromIntegrationSuccess,
@ -18,12 +21,14 @@ import {
IntegrationsSuccess,
IntegrationSuccess,
MutationDeleteIntegrationArgs,
MutationExportToIntegrationArgs,
MutationImportFromIntegrationArgs,
MutationSetIntegrationArgs,
QueryIntegrationArgs,
SetIntegrationError,
SetIntegrationErrorCode,
SetIntegrationSuccess,
TaskState,
} from '../../generated/graphql'
import { createIntegrationToken } from '../../routers/auth/jwt_helpers'
import {
@ -38,6 +43,7 @@ import {
import { analytics } from '../../utils/analytics'
import {
deleteTask,
enqueueExportToIntegration,
enqueueImportFromIntegration,
} from '../../utils/createTask'
import { authorized } from '../../utils/gql-utils'
@ -216,3 +222,52 @@ export const importFromIntegrationResolver = authorized<
success: true,
}
})
export const exportToIntegrationResolver = authorized<
ExportToIntegrationSuccess,
ExportToIntegrationError,
MutationExportToIntegrationArgs
>(async (_, { integrationId }, { uid, log }) => {
const integration = await findIntegration({ id: integrationId }, uid)
if (!integration) {
log.error('integration not found', integrationId)
return {
errorCodes: [ExportToIntegrationErrorCode.Unauthorized],
}
}
// create a job to export all the items
const job = await enqueueExportToIntegration(integration.id, uid)
if (!job || !job.id) {
log.error('failed to create task', integrationId)
return {
errorCodes: [ExportToIntegrationErrorCode.FailedToCreateTask],
}
}
// update task name in integration
await updateIntegration(integration.id, { taskName: job.id }, uid)
analytics.capture({
distinctId: uid,
event: 'integration_export',
properties: {
integrationId,
},
})
return {
task: {
id: job.id,
name: job.name,
state: TaskState.Pending,
createdAt: new Date(job.timestamp),
progress: 0,
runningTime: 0,
cancellable: true,
},
}
})

View file

@ -1,65 +0,0 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import express from 'express'
import { Integration, IntegrationType } from '../../entity/integration'
import { readPushSubscription } from '../../pubsub'
import { getRepository } from '../../repository'
import { enqueueExportAllItems } from '../../utils/createTask'
import { logger } from '../../utils/logger'
import { createIntegrationToken } from '../auth/jwt_helpers'
export function integrationsServiceRouter() {
const router = express.Router()
router.post('/export', async (req, res) => {
logger.info('start to sync with integration')
try {
const { message: msgStr, expired } = readPushSubscription(req)
if (!msgStr) {
return res.status(200).send('Bad Request')
}
if (expired) {
logger.info('discarding expired message')
return res.status(200).send('Expired')
}
// find all active integrations
const integrations = await getRepository(Integration).find({
where: {
enabled: true,
type: IntegrationType.Export,
},
relations: ['user'],
})
// create a task to sync with each integration
await Promise.all(
integrations.map(async (integration) => {
const authToken = await createIntegrationToken({
uid: integration.user.id,
token: integration.token,
})
if (!authToken) {
logger.error('failed to create auth token', {
integrationId: integration.id,
})
return
}
return enqueueExportAllItems(integration.id, integration.user.id)
})
)
} catch (err) {
logger.error('sync with integrations failed', err)
return res.status(500).send(err)
}
res.status(200).send('OK')
})
return router
}

View file

@ -0,0 +1,49 @@
import cors from 'cors'
import express from 'express'
import { Task, TaskState } from '../generated/graphql'
import { getJob, jobStateToTaskState } from '../queue-processor'
import { getClaimsByToken, getTokenByRequest } from '../utils/auth'
import { corsConfig } from '../utils/corsConfig'
import { logger } from '../utils/logger'
export function taskRouter() {
const router = express.Router()
router.get('/:id', cors<express.Request>(corsConfig), async (req, res) => {
const token = getTokenByRequest(req)
const claims = await getClaimsByToken(token)
if (!claims) {
return res.status(401).send('UNAUTHORIZED')
}
try {
const job = await getJob(req.params.id)
if (!job || !job.id) {
res.status(404).send('Not Found')
return
}
const jobState = await job.getState()
const state = jobStateToTaskState(jobState)
const finishedAt = job.finishedOn ? job.finishedOn : Date.now()
const runningTime = job.processedOn ? finishedAt - job.processedOn : 0
const result: Task = {
id: job.id,
state,
createdAt: new Date(job.timestamp),
name: job.name,
runningTime,
progress: job.progress as number,
failedReason: state === TaskState.Failed ? job.failedReason : undefined,
}
res.send(result)
} catch (e) {
logger.error('failed to get task', e)
res.status(500)
}
})
return router
}

View file

@ -3023,6 +3023,42 @@ const schema = gql`
NOT_FOUND
}
union ExportToIntegrationResult =
ExportToIntegrationSuccess
| ExportToIntegrationError
type ExportToIntegrationSuccess {
task: Task!
}
type Task {
id: ID!
name: String!
state: TaskState!
createdAt: Date!
runningTime: Int # in milliseconds
cancellable: Boolean
progress: Float
failedReason: String
}
enum TaskState {
PENDING
RUNNING
SUCCEEDED
FAILED
CANCELLED
}
type ExportToIntegrationError {
errorCodes: [ExportToIntegrationErrorCode!]!
}
enum ExportToIntegrationErrorCode {
UNAUTHORIZED
FAILED_TO_CREATE_TASK
}
# Mutations
type Mutation {
googleLogin(input: GoogleLoginInput!): LoginResult!
@ -3131,6 +3167,7 @@ const schema = gql`
arguments: JSON # additional arguments for the action
): BulkActionResult!
importFromIntegration(integrationId: ID!): ImportFromIntegrationResult!
exportToIntegration(integrationId: ID!): ExportToIntegrationResult!
setFavoriteArticle(id: ID!): SetFavoriteArticleResult!
updateSubscription(
input: UpdateSubscriptionInput!

View file

@ -18,6 +18,7 @@ import { makeApolloServer } from './apollo'
import { appDataSource } from './data_source'
import { env } from './env'
import { redisDataSource } from './redis_data_source'
import { aiSummariesRouter } from './routers/ai_summary_router'
import { articleRouter } from './routers/article_router'
import { authRouter } from './routers/auth/auth_router'
import { mobileAuthRouter } from './routers/auth/mobile/mobile_auth_router'
@ -29,7 +30,6 @@ import { contentServiceRouter } from './routers/svc/content'
import { emailsServiceRouter } from './routers/svc/emails'
import { emailAttachmentRouter } from './routers/svc/email_attachment'
import { followingServiceRouter } from './routers/svc/following'
import { integrationsServiceRouter } from './routers/svc/integrations'
import { linkServiceRouter } from './routers/svc/links'
import { newsletterServiceRouter } from './routers/svc/newsletters'
// import { remindersServiceRouter } from './routers/svc/reminders'
@ -37,6 +37,7 @@ import { rssFeedRouter } from './routers/svc/rss_feed'
import { uploadServiceRouter } from './routers/svc/upload'
import { userServiceRouter } from './routers/svc/user'
import { webhooksServiceRouter } from './routers/svc/webhooks'
import { taskRouter } from './routers/task_router'
import { textToSpeechRouter } from './routers/text_to_speech'
import { userRouter } from './routers/user_router'
import { sentryConfig } from './sentry'
@ -48,7 +49,6 @@ import {
} from './utils/auth'
import { corsConfig } from './utils/corsConfig'
import { buildLogger, buildLoggerTransport, logger } from './utils/logger'
import { aiSummariesRouter } from './routers/ai_summary_router'
const PORT = process.env.PORT || 4000
@ -126,13 +126,13 @@ export const createApp = (): {
app.use('/api/text-to-speech', textToSpeechRouter())
app.use('/api/notification', notificationRouter())
app.use('/api/integration', integrationRouter())
app.use('/api/tasks', taskRouter())
app.use('/svc/pubsub/content', contentServiceRouter())
app.use('/svc/pubsub/links', linkServiceRouter())
app.use('/svc/pubsub/newsletters', newsletterServiceRouter())
app.use('/svc/pubsub/emails', emailsServiceRouter())
app.use('/svc/pubsub/upload', uploadServiceRouter())
app.use('/svc/pubsub/webhooks', webhooksServiceRouter())
app.use('/svc/pubsub/integrations', integrationsServiceRouter())
app.use('/svc/pubsub/rss-feed', rssFeedRouter())
app.use('/svc/pubsub/user', userServiceRouter())
// app.use('/svc/reminders', remindersServiceRouter())

View file

@ -15,6 +15,7 @@ import {
ArticleSavingRequestStatus,
CreateLabelInput,
} from '../generated/graphql'
import { AISummarizeJobData, AI_SUMMARIZE_JOB_NAME } from '../jobs/ai-summarize'
import { BulkActionData, BULK_ACTION_JOB_NAME } from '../jobs/bulk_action'
import { CallWebhookJobData, CALL_WEBHOOK_JOB_NAME } from '../jobs/call_webhook'
import { THUMBNAIL_JOB } from '../jobs/find_thumbnail'
@ -23,6 +24,12 @@ import {
ExportItemJobData,
EXPORT_ITEM_JOB_NAME,
} from '../jobs/integration/export_item'
import {
ProcessYouTubeTranscriptJobData,
ProcessYouTubeVideoJobData,
PROCESS_YOUTUBE_TRANSCRIPT_JOB_NAME,
PROCESS_YOUTUBE_VIDEO_JOB_NAME,
} from '../jobs/process-youtube-video'
import {
queueRSSRefreshFeedJob,
REFRESH_ALL_FEEDS_JOB_NAME,
@ -44,13 +51,6 @@ import { CreateTaskError } from './errors'
import { stringToHash } from './helpers'
import { logger } from './logger'
import View = google.cloud.tasks.v2.Task.View
import { AISummarizeJobData, AI_SUMMARIZE_JOB_NAME } from '../jobs/ai-summarize'
import {
PROCESS_YOUTUBE_TRANSCRIPT_JOB_NAME,
PROCESS_YOUTUBE_VIDEO_JOB_NAME,
ProcessYouTubeTranscriptJobData,
ProcessYouTubeVideoJobData,
} from '../jobs/process-youtube-video'
// Instantiates a client.
const client = new CloudTasksClient()
@ -594,7 +594,7 @@ export const enqueueImportFromIntegration = async (
return createdTasks[0].name
}
export const enqueueExportAllItems = async (
export const enqueueExportToIntegration = async (
integrationId: string,
userId: string
) => {