mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Merge pull request #634 from omnivore-app/OMN-626
[Omn-626] - API to edit title and/or description
This commit is contained in:
commit
8e30d793e0
7 changed files with 237 additions and 0 deletions
|
|
@ -823,6 +823,7 @@ export type Mutation = {
|
|||
updateHighlightReply: UpdateHighlightReplyResult;
|
||||
updateLabel: UpdateLabelResult;
|
||||
updateLinkShareInfo: UpdateLinkShareInfoResult;
|
||||
updatePage: UpdatePageResult;
|
||||
updateReminder: UpdateReminderResult;
|
||||
updateSharedComment: UpdateSharedCommentResult;
|
||||
updateUser: UpdateUserResult;
|
||||
|
|
@ -1021,6 +1022,11 @@ export type MutationUpdateLinkShareInfoArgs = {
|
|||
};
|
||||
|
||||
|
||||
export type MutationUpdatePageArgs = {
|
||||
input: UpdatePageInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateReminderArgs = {
|
||||
input: UpdateReminderInput;
|
||||
};
|
||||
|
|
@ -1822,6 +1828,32 @@ export type UpdateLinkShareInfoSuccess = {
|
|||
message: Scalars['String'];
|
||||
};
|
||||
|
||||
export type UpdatePageError = {
|
||||
__typename?: 'UpdatePageError';
|
||||
errorCodes: Array<UpdatePageErrorCode>;
|
||||
};
|
||||
|
||||
export enum UpdatePageErrorCode {
|
||||
BadRequest = 'BAD_REQUEST',
|
||||
Forbidden = 'FORBIDDEN',
|
||||
NotFound = 'NOT_FOUND',
|
||||
Unauthorized = 'UNAUTHORIZED',
|
||||
UpdateFailed = 'UPDATE_FAILED'
|
||||
}
|
||||
|
||||
export type UpdatePageInput = {
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
pageId: Scalars['ID'];
|
||||
title?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type UpdatePageResult = UpdatePageError | UpdatePageSuccess;
|
||||
|
||||
export type UpdatePageSuccess = {
|
||||
__typename?: 'UpdatePageSuccess';
|
||||
updatedPage: Page;
|
||||
};
|
||||
|
||||
export type UpdateReminderError = {
|
||||
__typename?: 'UpdateReminderError';
|
||||
errorCodes: Array<UpdateReminderErrorCode>;
|
||||
|
|
@ -2352,6 +2384,11 @@ export type ResolversTypes = {
|
|||
UpdateLinkShareInfoInput: UpdateLinkShareInfoInput;
|
||||
UpdateLinkShareInfoResult: ResolversTypes['UpdateLinkShareInfoError'] | ResolversTypes['UpdateLinkShareInfoSuccess'];
|
||||
UpdateLinkShareInfoSuccess: ResolverTypeWrapper<UpdateLinkShareInfoSuccess>;
|
||||
UpdatePageError: ResolverTypeWrapper<UpdatePageError>;
|
||||
UpdatePageErrorCode: UpdatePageErrorCode;
|
||||
UpdatePageInput: UpdatePageInput;
|
||||
UpdatePageResult: ResolversTypes['UpdatePageError'] | ResolversTypes['UpdatePageSuccess'];
|
||||
UpdatePageSuccess: ResolverTypeWrapper<UpdatePageSuccess>;
|
||||
UpdateReminderError: ResolverTypeWrapper<UpdateReminderError>;
|
||||
UpdateReminderErrorCode: UpdateReminderErrorCode;
|
||||
UpdateReminderInput: UpdateReminderInput;
|
||||
|
|
@ -2605,6 +2642,10 @@ export type ResolversParentTypes = {
|
|||
UpdateLinkShareInfoInput: UpdateLinkShareInfoInput;
|
||||
UpdateLinkShareInfoResult: ResolversParentTypes['UpdateLinkShareInfoError'] | ResolversParentTypes['UpdateLinkShareInfoSuccess'];
|
||||
UpdateLinkShareInfoSuccess: UpdateLinkShareInfoSuccess;
|
||||
UpdatePageError: UpdatePageError;
|
||||
UpdatePageInput: UpdatePageInput;
|
||||
UpdatePageResult: ResolversParentTypes['UpdatePageError'] | ResolversParentTypes['UpdatePageSuccess'];
|
||||
UpdatePageSuccess: UpdatePageSuccess;
|
||||
UpdateReminderError: UpdateReminderError;
|
||||
UpdateReminderInput: UpdateReminderInput;
|
||||
UpdateReminderResult: ResolversParentTypes['UpdateReminderError'] | ResolversParentTypes['UpdateReminderSuccess'];
|
||||
|
|
@ -3236,6 +3277,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
|
|||
updateHighlightReply?: Resolver<ResolversTypes['UpdateHighlightReplyResult'], ParentType, ContextType, RequireFields<MutationUpdateHighlightReplyArgs, 'input'>>;
|
||||
updateLabel?: Resolver<ResolversTypes['UpdateLabelResult'], ParentType, ContextType, RequireFields<MutationUpdateLabelArgs, 'input'>>;
|
||||
updateLinkShareInfo?: Resolver<ResolversTypes['UpdateLinkShareInfoResult'], ParentType, ContextType, RequireFields<MutationUpdateLinkShareInfoArgs, 'input'>>;
|
||||
updatePage?: Resolver<ResolversTypes['UpdatePageResult'], ParentType, ContextType, RequireFields<MutationUpdatePageArgs, 'input'>>;
|
||||
updateReminder?: Resolver<ResolversTypes['UpdateReminderResult'], ParentType, ContextType, RequireFields<MutationUpdateReminderArgs, 'input'>>;
|
||||
updateSharedComment?: Resolver<ResolversTypes['UpdateSharedCommentResult'], ParentType, ContextType, RequireFields<MutationUpdateSharedCommentArgs, 'input'>>;
|
||||
updateUser?: Resolver<ResolversTypes['UpdateUserResult'], ParentType, ContextType, RequireFields<MutationUpdateUserArgs, 'input'>>;
|
||||
|
|
@ -3692,6 +3734,20 @@ export type UpdateLinkShareInfoSuccessResolvers<ContextType = ResolverContext, P
|
|||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type UpdatePageErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdatePageError'] = ResolversParentTypes['UpdatePageError']> = {
|
||||
errorCodes?: Resolver<Array<ResolversTypes['UpdatePageErrorCode']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type UpdatePageResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdatePageResult'] = ResolversParentTypes['UpdatePageResult']> = {
|
||||
__resolveType: TypeResolveFn<'UpdatePageError' | 'UpdatePageSuccess', ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type UpdatePageSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdatePageSuccess'] = ResolversParentTypes['UpdatePageSuccess']> = {
|
||||
updatedPage?: Resolver<ResolversTypes['Page'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type UpdateReminderErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdateReminderError'] = ResolversParentTypes['UpdateReminderError']> = {
|
||||
errorCodes?: Resolver<Array<ResolversTypes['UpdateReminderErrorCode']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
|
|
@ -3996,6 +4052,9 @@ export type Resolvers<ContextType = ResolverContext> = {
|
|||
UpdateLinkShareInfoError?: UpdateLinkShareInfoErrorResolvers<ContextType>;
|
||||
UpdateLinkShareInfoResult?: UpdateLinkShareInfoResultResolvers<ContextType>;
|
||||
UpdateLinkShareInfoSuccess?: UpdateLinkShareInfoSuccessResolvers<ContextType>;
|
||||
UpdatePageError?: UpdatePageErrorResolvers<ContextType>;
|
||||
UpdatePageResult?: UpdatePageResultResolvers<ContextType>;
|
||||
UpdatePageSuccess?: UpdatePageSuccessResolvers<ContextType>;
|
||||
UpdateReminderError?: UpdateReminderErrorResolvers<ContextType>;
|
||||
UpdateReminderResult?: UpdateReminderResultResolvers<ContextType>;
|
||||
UpdateReminderSuccess?: UpdateReminderSuccessResolvers<ContextType>;
|
||||
|
|
|
|||
|
|
@ -733,6 +733,7 @@ type Mutation {
|
|||
updateHighlightReply(input: UpdateHighlightReplyInput!): UpdateHighlightReplyResult!
|
||||
updateLabel(input: UpdateLabelInput!): UpdateLabelResult!
|
||||
updateLinkShareInfo(input: UpdateLinkShareInfoInput!): UpdateLinkShareInfoResult!
|
||||
updatePage(input: UpdatePageInput!): UpdatePageResult!
|
||||
updateReminder(input: UpdateReminderInput!): UpdateReminderResult!
|
||||
updateSharedComment(input: UpdateSharedCommentInput!): UpdateSharedCommentResult!
|
||||
updateUser(input: UpdateUserInput!): UpdateUserResult!
|
||||
|
|
@ -1388,6 +1389,30 @@ type UpdateLinkShareInfoSuccess {
|
|||
message: String!
|
||||
}
|
||||
|
||||
type UpdatePageError {
|
||||
errorCodes: [UpdatePageErrorCode!]!
|
||||
}
|
||||
|
||||
enum UpdatePageErrorCode {
|
||||
BAD_REQUEST
|
||||
FORBIDDEN
|
||||
NOT_FOUND
|
||||
UNAUTHORIZED
|
||||
UPDATE_FAILED
|
||||
}
|
||||
|
||||
input UpdatePageInput {
|
||||
description: String
|
||||
pageId: ID!
|
||||
title: String
|
||||
}
|
||||
|
||||
union UpdatePageResult = UpdatePageError | UpdatePageSuccess
|
||||
|
||||
type UpdatePageSuccess {
|
||||
updatedPage: Page!
|
||||
}
|
||||
|
||||
type UpdateReminderError {
|
||||
errorCodes: [UpdateReminderErrorCode!]!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ import {
|
|||
updateUserResolver,
|
||||
uploadFileRequestResolver,
|
||||
validateUsernameResolver,
|
||||
updatePageResolver,
|
||||
} from './index'
|
||||
import { getShareInfoForArticle } from '../datalayer/links/share_info'
|
||||
import {
|
||||
|
|
@ -146,6 +147,7 @@ export const functionResolvers = {
|
|||
setLabels: setLabelsResolver,
|
||||
generateApiKey: generateApiKeyResolver,
|
||||
unsubscribe: unsubscribeResolver,
|
||||
updatePage: updatePageResolver,
|
||||
subscribe: subscribeResolver,
|
||||
},
|
||||
Query: {
|
||||
|
|
@ -556,5 +558,6 @@ export const functionResolvers = {
|
|||
...resultResolveTypeResolver('Subscriptions'),
|
||||
...resultResolveTypeResolver('Unsubscribe'),
|
||||
...resultResolveTypeResolver('UpdateLabel'),
|
||||
...resultResolveTypeResolver('UpdatePage'),
|
||||
...resultResolveTypeResolver('Subscribe'),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,3 +15,4 @@ export * from './reminders'
|
|||
export * from './user_device_tokens'
|
||||
export * from './labels'
|
||||
export * from './subscriptions'
|
||||
export * from './update'
|
||||
|
|
|
|||
52
packages/api/src/resolvers/update/index.ts
Normal file
52
packages/api/src/resolvers/update/index.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import {
|
||||
UpdatePageError,
|
||||
UpdatePageErrorCode,
|
||||
UpdatePageSuccess,
|
||||
MutationUpdatePageArgs,
|
||||
} from '../../generated/graphql'
|
||||
import { authorized, userDataToUser } from '../../utils/helpers'
|
||||
import { updatePage, getPageById } from '../../elastic/pages'
|
||||
import { Page } from '../../entity/page'
|
||||
import { Merge } from '../../util'
|
||||
|
||||
export type UpdatePageSuccessPartial = Merge<
|
||||
UpdatePageSuccess,
|
||||
{ updatedPage: Partial<Page> }
|
||||
>
|
||||
|
||||
export const updatePageResolver = authorized<
|
||||
UpdatePageSuccessPartial,
|
||||
UpdatePageError,
|
||||
MutationUpdatePageArgs
|
||||
>(async (_, { input }, ctx) => {
|
||||
const {
|
||||
models,
|
||||
claims: { uid },
|
||||
} = ctx
|
||||
|
||||
const user = userDataToUser(await models.user.get(uid))
|
||||
if (!user) {
|
||||
return { errorCodes: [UpdatePageErrorCode.Unauthorized] }
|
||||
}
|
||||
|
||||
const page = await getPageById(input.pageId)
|
||||
|
||||
if (!page) return { errorCodes: [UpdatePageErrorCode.NotFound] }
|
||||
else if (page.userId !== user.id)
|
||||
return { errorCodes: [UpdatePageErrorCode.Unauthorized] }
|
||||
|
||||
const pageData = {
|
||||
id: input.pageId,
|
||||
title: input.title || undefined,
|
||||
description: input.description || '',
|
||||
}
|
||||
|
||||
const updateResult = await updatePage(input.pageId, pageData, { ...ctx, uid })
|
||||
if (!updateResult) return { errorCodes: [UpdatePageErrorCode.UpdateFailed] }
|
||||
|
||||
const updatedPage = (await getPageById(input.pageId)) as unknown as Page
|
||||
return {
|
||||
updatedPage: updatedPage,
|
||||
__typename: 'UpdatePageSuccess',
|
||||
}
|
||||
})
|
||||
|
|
@ -498,6 +498,30 @@ const schema = gql`
|
|||
|
||||
union SaveResult = SaveSuccess | SaveError
|
||||
|
||||
input UpdatePageInput {
|
||||
pageId: ID!
|
||||
title: String
|
||||
description: String
|
||||
}
|
||||
|
||||
type UpdatePageSuccess {
|
||||
updatedPage: Page!
|
||||
}
|
||||
|
||||
enum UpdatePageErrorCode {
|
||||
UPDATE_FAILED
|
||||
UNAUTHORIZED
|
||||
BAD_REQUEST
|
||||
NOT_FOUND
|
||||
FORBIDDEN
|
||||
}
|
||||
|
||||
type UpdatePageError {
|
||||
errorCodes: [UpdatePageErrorCode!]!
|
||||
}
|
||||
|
||||
union UpdatePageResult = UpdatePageSuccess | UpdatePageError
|
||||
|
||||
# Mutation: setFollow
|
||||
union SetFollowResult = SetFollowSuccess | SetFollowError
|
||||
input SetFollowInput {
|
||||
|
|
@ -1577,6 +1601,7 @@ const schema = gql`
|
|||
deleteNewsletterEmail(newsletterEmailId: ID!): DeleteNewsletterEmailResult!
|
||||
saveUrl(input: SaveUrlInput!): SaveResult!
|
||||
savePage(input: SavePageInput!): SaveResult!
|
||||
updatePage(input: UpdatePageInput!): UpdatePageResult!
|
||||
saveFile(input: SaveFileInput!): SaveResult!
|
||||
createReminder(input: CreateReminderInput!): CreateReminderResult!
|
||||
updateReminder(input: UpdateReminderInput!): UpdateReminderResult!
|
||||
|
|
|
|||
72
packages/api/test/resolvers/update.test.ts
Normal file
72
packages/api/test/resolvers/update.test.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import { createTestUser, deleteTestUser } from '../db'
|
||||
import {
|
||||
createTestElasticPage,
|
||||
graphqlRequest,
|
||||
request,
|
||||
} from '../util'
|
||||
import { expect } from 'chai'
|
||||
import 'mocha'
|
||||
import { User } from '../../src/entity/user'
|
||||
import { Page } from '../../src/elastic/types'
|
||||
|
||||
describe('Update API', () => {
|
||||
const username = 'fakeUser'
|
||||
|
||||
let user: User
|
||||
let authToken: string
|
||||
let page: Page
|
||||
|
||||
before(async () => {
|
||||
// create test user and login
|
||||
user = await createTestUser(username)
|
||||
const res = await request
|
||||
.post('/local/debug/fake-user-login')
|
||||
.send({ fakeEmail: user.email })
|
||||
|
||||
authToken = res.body.authToken
|
||||
page = await createTestElasticPage(user)
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
// clean up
|
||||
await deleteTestUser(username)
|
||||
})
|
||||
|
||||
describe('update page', () => {
|
||||
let query: string
|
||||
let title = "New Title"
|
||||
let description = "New Description"
|
||||
|
||||
beforeEach(() => {
|
||||
query = `
|
||||
mutation {
|
||||
updatePage(
|
||||
input: {
|
||||
pageId: "${page.id}"
|
||||
title: "${title}"
|
||||
description: "${description}"
|
||||
}
|
||||
) {
|
||||
... on UpdatePageSuccess {
|
||||
updatedPage {
|
||||
title
|
||||
description
|
||||
}
|
||||
}
|
||||
... on UpdatePageError {
|
||||
errorCodes
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
})
|
||||
|
||||
it('should update page', async () => {
|
||||
const res = await graphqlRequest(query, authToken).expect(200)
|
||||
|
||||
const updatedPage = res?.body.data.updatePage.updatedPage
|
||||
expect(updatedPage?.title).to.eql(title)
|
||||
expect(updatedPage?.description).to.eql(description)
|
||||
})
|
||||
})
|
||||
})
|
||||
Loading…
Reference in a new issue