From 864f9db753c5c3c1c99885c5889d0bdd261e6163 Mon Sep 17 00:00:00 2001 From: roschaefer Date: Thu, 14 Nov 2019 12:56:00 +0100 Subject: [PATCH 1/4] Remove potentially unused code --- backend/src/bootstrap/directives.js | 12 ---- backend/src/bootstrap/scalars.js | 9 --- backend/src/schema/index.js | 94 +++++++++++++---------------- 3 files changed, 42 insertions(+), 73 deletions(-) delete mode 100644 backend/src/bootstrap/directives.js delete mode 100644 backend/src/bootstrap/scalars.js diff --git a/backend/src/bootstrap/directives.js b/backend/src/bootstrap/directives.js deleted file mode 100644 index 93a7574fb..000000000 --- a/backend/src/bootstrap/directives.js +++ /dev/null @@ -1,12 +0,0 @@ -import { - GraphQLLowerCaseDirective, - GraphQLTrimDirective, - GraphQLDefaultToDirective, -} from 'graphql-custom-directives' - -export default function applyDirectives(augmentedSchema) { - const directives = [GraphQLLowerCaseDirective, GraphQLTrimDirective, GraphQLDefaultToDirective] - augmentedSchema._directives.push.apply(augmentedSchema._directives, directives) - - return augmentedSchema -} diff --git a/backend/src/bootstrap/scalars.js b/backend/src/bootstrap/scalars.js deleted file mode 100644 index eb6d3739b..000000000 --- a/backend/src/bootstrap/scalars.js +++ /dev/null @@ -1,9 +0,0 @@ -import { GraphQLDate, GraphQLTime, GraphQLDateTime } from 'graphql-iso-date' - -export default function applyScalars(augmentedSchema) { - augmentedSchema._typeMap.Date = GraphQLDate - augmentedSchema._typeMap.Time = GraphQLTime - augmentedSchema._typeMap.DateTime = GraphQLDateTime - - return augmentedSchema -} diff --git a/backend/src/schema/index.js b/backend/src/schema/index.js index b1bd36451..695e448b3 100644 --- a/backend/src/schema/index.js +++ b/backend/src/schema/index.js @@ -1,56 +1,46 @@ import { makeAugmentedSchema } from 'neo4j-graphql-js' -import CONFIG from './../config' -import applyScalars from './../bootstrap/scalars' -import applyDirectives from './../bootstrap/directives' import typeDefs from './types' import resolvers from './resolvers' -export default applyScalars( - applyDirectives( - makeAugmentedSchema({ - typeDefs, - resolvers, - config: { - query: { - exclude: [ - 'Badge', - 'Embed', - 'InvitationCode', - 'EmailAddress', - 'Notfication', - 'Statistics', - 'LoggedInUser', - 'Location', - 'SocialMedia', - 'NOTIFIED', - 'REPORTED', - 'Donations', - ], - // add 'User' here as soon as possible - }, - mutation: { - exclude: [ - 'Badge', - 'Embed', - 'InvitationCode', - 'EmailAddress', - 'Notfication', - 'Post', - 'Comment', - 'Statistics', - 'LoggedInUser', - 'Location', - 'SocialMedia', - 'User', - 'EMOTED', - 'NOTIFIED', - 'REPORTED', - 'Donations', - ], - // add 'User' here as soon as possible - }, - debug: !!CONFIG.DEBUG, - }, - }), - ), -) +export default makeAugmentedSchema({ + typeDefs, + resolvers, + config: { + query: { + exclude: [ + 'Badge', + 'Embed', + 'InvitationCode', + 'EmailAddress', + 'Notfication', + 'Statistics', + 'LoggedInUser', + 'Location', + 'SocialMedia', + 'NOTIFIED', + 'REPORTED', + ], + // add 'User' here as soon as possible + }, + mutation: { + exclude: [ + 'Badge', + 'Embed', + 'InvitationCode', + 'EmailAddress', + 'Notfication', + 'Post', + 'Comment', + 'Statistics', + 'LoggedInUser', + 'Location', + 'SocialMedia', + 'User', + 'EMOTED', + 'NOTIFIED', + 'REPORTED', + ], + // add 'User' here as soon as possible + }, + }, +}) From 034a353367ad46a9dac9bf4f76f8388eb1c619fa Mon Sep 17 00:00:00 2001 From: roschaefer Date: Thu, 14 Nov 2019 21:44:40 +0100 Subject: [PATCH 2/4] Hard-code graphql schema Apparently, `neo4j-graphql-js` *replaces* the schema partly. When we use join models like `EMOTED`, `neo4j-graphql-js` puts in a join model with the two names of the connected types. --- backend/src/middleware/sluggifyMiddleware.js | 4 - backend/src/schema/helpers.js | 9 -- backend/src/schema/index.js | 23 +--- backend/src/schema/resolvers/posts.js | 2 +- backend/src/schema/resolvers/posts.spec.js | 11 +- backend/src/schema/types/scalar/Date.gql_ | 1 - backend/src/schema/types/scalar/DateTime.gql_ | 1 - backend/src/schema/types/scalar/Time.gql_ | 1 - backend/src/schema/types/type/Badge.gql | 2 - backend/src/schema/types/type/Category.gql | 32 ++++- backend/src/schema/types/type/Comment.gql | 51 ++++++++ backend/src/schema/types/type/EMOTED.gql | 2 - .../src/schema/types/type/InvitationCode.gql | 3 - backend/src/schema/types/type/Post.gql | 113 ++++++++++++++++-- backend/src/schema/types/type/Tag.gql | 32 +++++ backend/src/schema/types/type/User.gql | 42 ++++--- 16 files changed, 249 insertions(+), 80 deletions(-) delete mode 100644 backend/src/schema/helpers.js delete mode 100644 backend/src/schema/types/scalar/Date.gql_ delete mode 100644 backend/src/schema/types/scalar/DateTime.gql_ delete mode 100644 backend/src/schema/types/scalar/Time.gql_ diff --git a/backend/src/middleware/sluggifyMiddleware.js b/backend/src/middleware/sluggifyMiddleware.js index 03d7f8584..fed9b4da7 100644 --- a/backend/src/middleware/sluggifyMiddleware.js +++ b/backend/src/middleware/sluggifyMiddleware.js @@ -25,9 +25,5 @@ export default { args.slug = args.slug || (await uniqueSlug(args.title, isUniqueFor(context, 'Post'))) return resolve(root, args, context, info) }, - CreateCategory: async (resolve, root, args, context, info) => { - args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'Category'))) - return resolve(root, args, context, info) - }, }, } diff --git a/backend/src/schema/helpers.js b/backend/src/schema/helpers.js deleted file mode 100644 index fe61ccf57..000000000 --- a/backend/src/schema/helpers.js +++ /dev/null @@ -1,9 +0,0 @@ -export const undefinedToNull = list => { - const resolvers = {} - list.forEach(key => { - resolvers[key] = async (parent, params, context, resolveInfo) => { - return typeof parent[key] === 'undefined' ? null : parent[key] - } - }) - return resolvers -} diff --git a/backend/src/schema/index.js b/backend/src/schema/index.js index 695e448b3..516f47abd 100644 --- a/backend/src/schema/index.js +++ b/backend/src/schema/index.js @@ -19,28 +19,9 @@ export default makeAugmentedSchema({ 'SocialMedia', 'NOTIFIED', 'REPORTED', + 'Donations', ], - // add 'User' here as soon as possible - }, - mutation: { - exclude: [ - 'Badge', - 'Embed', - 'InvitationCode', - 'EmailAddress', - 'Notfication', - 'Post', - 'Comment', - 'Statistics', - 'LoggedInUser', - 'Location', - 'SocialMedia', - 'User', - 'EMOTED', - 'NOTIFIED', - 'REPORTED', - ], - // add 'User' here as soon as possible }, + mutation: false, }, }) diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index 0f2fd8e78..ee6a82d42 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -29,7 +29,7 @@ const filterForBlockedUsers = async (params, context) => { } const maintainPinnedPosts = params => { - const pinnedPostFilter = { pinnedBy_in: { role_in: ['admin'] } } + const pinnedPostFilter = { pinned: true } if (isEmpty(params.filter)) { params.filter = { OR: [pinnedPostFilter, {}] } } else { diff --git a/backend/src/schema/resolvers/posts.spec.js b/backend/src/schema/resolvers/posts.spec.js index 9106e4eb9..005c18cd7 100644 --- a/backend/src/schema/resolvers/posts.spec.js +++ b/backend/src/schema/resolvers/posts.spec.js @@ -210,6 +210,7 @@ describe('Post', () => { data: { Post: expect.arrayContaining(expected), }, + errors: undefined, }) }) }) @@ -229,7 +230,9 @@ describe('Post', () => { await user.relateTo(followedUser, 'following') variables = { filter: { author: { followedBy_some: { id: 'current-user' } } } } - const expected = { + await expect( + query({ query: postQueryFilteredByUsersFollowed, variables }), + ).resolves.toMatchObject({ data: { Post: [ { @@ -238,10 +241,8 @@ describe('Post', () => { }, ], }, - } - await expect( - query({ query: postQueryFilteredByUsersFollowed, variables }), - ).resolves.toMatchObject(expected) + errors: undefined, + }) }) }) }) diff --git a/backend/src/schema/types/scalar/Date.gql_ b/backend/src/schema/types/scalar/Date.gql_ deleted file mode 100644 index 7b0004ea3..000000000 --- a/backend/src/schema/types/scalar/Date.gql_ +++ /dev/null @@ -1 +0,0 @@ -scalar Date \ No newline at end of file diff --git a/backend/src/schema/types/scalar/DateTime.gql_ b/backend/src/schema/types/scalar/DateTime.gql_ deleted file mode 100644 index af973932f..000000000 --- a/backend/src/schema/types/scalar/DateTime.gql_ +++ /dev/null @@ -1 +0,0 @@ -scalar DateTime \ No newline at end of file diff --git a/backend/src/schema/types/scalar/Time.gql_ b/backend/src/schema/types/scalar/Time.gql_ deleted file mode 100644 index 53becdd66..000000000 --- a/backend/src/schema/types/scalar/Time.gql_ +++ /dev/null @@ -1 +0,0 @@ -scalar Time \ No newline at end of file diff --git a/backend/src/schema/types/type/Badge.gql b/backend/src/schema/types/type/Badge.gql index 99015a518..dff1de89a 100644 --- a/backend/src/schema/types/type/Badge.gql +++ b/backend/src/schema/types/type/Badge.gql @@ -3,8 +3,6 @@ type Badge { type: BadgeType! status: BadgeStatus! icon: String! - #createdAt: DateTime - #updatedAt: DateTime createdAt: String updatedAt: String diff --git a/backend/src/schema/types/type/Category.gql b/backend/src/schema/types/type/Category.gql index 9ee628d76..9805344d1 100644 --- a/backend/src/schema/types/type/Category.gql +++ b/backend/src/schema/types/type/Category.gql @@ -1,13 +1,39 @@ +enum _CategoryOrdering { + id_asc + id_desc + name_asc + name_desc + slug_asc + slug_desc + icon_asc + icon_desc + createdAt_asc + createdAt_desc + updatedAt_asc + updatedAt_desc +} + type Category { id: ID! name: String! slug: String icon: String! - #createdAt: DateTime - #updatedAt: DateTime createdAt: String updatedAt: String - posts: [Post]! @relation(name: "CATEGORIZED", direction: "IN") postCount: Int! @cypher(statement: "MATCH (this)<-[:CATEGORIZED]-(r:Post) RETURN COUNT(r)") } + +type Query { + Category( + id: ID + name: String + slug: String + icon: String + createdAt: String + updatedAt: String + first: Int + offset: Int + orderBy: [_CategoryOrdering] + ): [Category] +} diff --git a/backend/src/schema/types/type/Comment.gql b/backend/src/schema/types/type/Comment.gql index 1ccf617ef..ba9d7a3fc 100644 --- a/backend/src/schema/types/type/Comment.gql +++ b/backend/src/schema/types/type/Comment.gql @@ -1,3 +1,41 @@ +enum _CommentOrdering { + id_asc + id_desc + content_asc + content_desc + createdAt_asc + createdAt_desc + updatedAt_asc + updatedAt_desc +} + +input _CommentFilter { + AND: [_CommentFilter!] + OR: [_CommentFilter!] + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + author: _UserFilter + author_not: _UserFilter + author_in: [_UserFilter!] + author_not_in: [_UserFilter!] + content: String + content_not: String + content_in: [String!] + content_not_in: [String!] + content_contains: String + content_not_contains: String + content_starts_with: String + content_not_starts_with: String + content_ends_with: String + content_not_ends_with: String + post: _PostFilter + post_not: _PostFilter + post_in: [_PostFilter!] + post_not_in: [_PostFilter!] +} + type Comment { id: ID! activityId: String @@ -12,6 +50,19 @@ type Comment { disabledBy: User @relation(name: "DISABLED", direction: "IN") } +type Query { + Comment( + id: ID + content: String + createdAt: String + updatedAt: String + first: Int + offset: Int + orderBy: [_CommentOrdering] + filter: _CommentFilter + ): [Comment] +} + type Mutation { CreateComment( id: ID diff --git a/backend/src/schema/types/type/EMOTED.gql b/backend/src/schema/types/type/EMOTED.gql index ee1576517..7a8b47b73 100644 --- a/backend/src/schema/types/type/EMOTED.gql +++ b/backend/src/schema/types/type/EMOTED.gql @@ -3,8 +3,6 @@ type EMOTED @relation(name: "EMOTED") { to: Post emotion: Emotion - # createdAt: DateTime - # updatedAt: DateTime createdAt: String updatedAt: String } diff --git a/backend/src/schema/types/type/InvitationCode.gql b/backend/src/schema/types/type/InvitationCode.gql index 044967286..61ce0f689 100644 --- a/backend/src/schema/types/type/InvitationCode.gql +++ b/backend/src/schema/types/type/InvitationCode.gql @@ -2,9 +2,6 @@ type InvitationCode { id: ID! token: String generatedBy: User @relation(name: "GENERATED", direction: "IN") - - #createdAt: DateTime - #usedAt: DateTime createdAt: String } diff --git a/backend/src/schema/types/type/Post.gql b/backend/src/schema/types/type/Post.gql index b4d98ec5c..a52558071 100644 --- a/backend/src/schema/types/type/Post.gql +++ b/backend/src/schema/types/type/Post.gql @@ -1,26 +1,101 @@ +input _PostFilter { + AND: [_PostFilter!] + OR: [_PostFilter!] + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + author: _UserFilter + author_not: _UserFilter + author_in: [_UserFilter!] + author_not_in: [_UserFilter!] + title: String + title_not: String + title_in: [String!] + title_not_in: [String!] + title_contains: String + title_not_contains: String + title_starts_with: String + title_not_starts_with: String + title_ends_with: String + title_not_ends_with: String + slug: String + slug_not: String + slug_in: [String!] + slug_not_in: [String!] + slug_contains: String + slug_not_contains: String + slug_starts_with: String + slug_not_starts_with: String + slug_ends_with: String + slug_not_ends_with: String + content: String + content_not: String + content_in: [String!] + content_not_in: [String!] + content_contains: String + content_not_contains: String + content_starts_with: String + content_not_starts_with: String + content_ends_with: String + content_not_ends_with: String + image: String + visibility: Visibility + visibility_not: Visibility + visibility_in: [Visibility!] + visibility_not_in: [Visibility!] + language: String + language_not: String + language_in: [String!] + language_not_in: [String!] + pinned: Boolean # required for `maintainPinnedPost` + tags: _TagFilter + tags_not: _TagFilter + tags_in: [_TagFilter!] + tags_not_in: [_TagFilter!] + tags_some: _TagFilter + tags_none: _TagFilter + tags_single: _TagFilter + tags_every: _TagFilter + categories: _CategoryFilter + categories_not: _CategoryFilter + categories_in: [_CategoryFilter!] + categories_not_in: [_CategoryFilter!] + categories_some: _CategoryFilter + categories_none: _CategoryFilter + categories_single: _CategoryFilter + categories_every: _CategoryFilter + comments: _CommentFilter + comments_not: _CommentFilter + comments_in: [_CommentFilter!] + comments_not_in: [_CommentFilter!] + comments_some: _CommentFilter + comments_none: _CommentFilter + comments_single: _CommentFilter + comments_every: _CommentFilter + emotions: _PostEMOTEDFilter + emotions_not: _PostEMOTEDFilter + emotions_in: [_PostEMOTEDFilter!] + emotions_not_in: [_PostEMOTEDFilter!] + emotions_some: _PostEMOTEDFilter + emotions_none: _PostEMOTEDFilter + emotions_single: _PostEMOTEDFilter + emotions_every: _PostEMOTEDFilter +} + enum _PostOrdering { id_asc id_desc - activityId_asc - activityId_desc - objectId_asc - objectId_desc title_asc title_desc slug_asc slug_desc content_asc content_desc - contentExcerpt_asc - contentExcerpt_desc image_asc image_desc visibility_asc visibility_desc - deleted_asc - deleted_desc - disabled_asc - disabled_desc createdAt_asc createdAt_desc updatedAt_asc @@ -79,7 +154,7 @@ type Post { @cypher( statement: "MATCH (this)<-[:SHOUTED]-(r:User) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)" ) - + # Has the currently logged in user shouted that post? shoutedByCurrentUser: Boolean! @cypher( @@ -128,6 +203,22 @@ type Mutation { } type Query { + Post( + id: ID + title: String + slug: String + content: String + image: String + visibility: Visibility + pinned: Boolean + createdAt: String + updatedAt: String + language: String + first: Int + offset: Int + orderBy: [_PostOrdering] + filter: _PostFilter + ): [Post] PostsEmotionsCountByEmotion(postId: ID!, data: _EMOTEDInput!): Int! PostsEmotionsByCurrentUser(postId: ID!): [String] profilePagePosts(filter: _PostFilter, first: Int, offset: Int, orderBy: [_PostOrdering]): [Post] diff --git a/backend/src/schema/types/type/Tag.gql b/backend/src/schema/types/type/Tag.gql index 84c6ee7e7..8da899027 100644 --- a/backend/src/schema/types/type/Tag.gql +++ b/backend/src/schema/types/type/Tag.gql @@ -1,3 +1,20 @@ +input _TagFilter { + AND: [_TagFilter!] + OR: [_TagFilter!] + id: ID + id_not: ID + id_in: [ID!] + id_not_in: [ID!] + taggedPosts: _PostFilter + taggedPosts_not: _PostFilter + taggedPosts_in: [_PostFilter!] + taggedPosts_not_in: [_PostFilter!] + taggedPosts_some: _PostFilter + taggedPosts_none: _PostFilter + taggedPosts_single: _PostFilter + taggedPosts_every: _PostFilter +} + type Tag { id: ID! taggedPosts: [Post]! @relation(name: "TAGGED", direction: "IN") @@ -6,3 +23,18 @@ type Tag { deleted: Boolean disabled: Boolean } + +enum _TagOrdering { + id_asc + id_desc +} + +type Query { + Tag( + id: ID + first: Int + offset: Int + orderBy: [_TagOrdering] + filter: _TagFilter + ): [Tag] +} diff --git a/backend/src/schema/types/type/User.gql b/backend/src/schema/types/type/User.gql index cce0df058..45cc549d8 100644 --- a/backend/src/schema/types/type/User.gql +++ b/backend/src/schema/types/type/User.gql @@ -1,3 +1,28 @@ +enum _UserOrdering { + id_asc + id_desc + name_asc + name_desc + slug_asc + slug_desc + avatar_asc + avatar_desc + coverImg_asc + coverImg_desc + role_asc + role_desc + locationName_asc + locationName_desc + about_asc + about_desc + createdAt_asc + createdAt_desc + updatedAt_asc + updatedAt_desc + locale_asc + locale_desc +} + type User { id: ID! actorId: String @@ -91,12 +116,6 @@ input _UserFilter { id_not: ID id_in: [ID!] id_not_in: [ID!] - id_contains: ID - id_not_contains: ID - id_starts_with: ID - id_not_starts_with: ID - id_ends_with: ID - id_not_ends_with: ID friends: _UserFilter friends_not: _UserFilter friends_in: [_UserFilter!] @@ -127,8 +146,7 @@ input _UserFilter { type Query { User( id: ID - email: String - actorId: String + email: String # admins need to search for a user sometimes name: String slug: String avatar: String @@ -138,14 +156,6 @@ type Query { about: String createdAt: String updatedAt: String - friendsCount: Int - followingCount: Int - followedByCount: Int - followedByCurrentUser: Boolean - contributionsCount: Int - commentedCount: Int - shoutedCount: Int - badgesCount: Int first: Int offset: Int orderBy: [_UserOrdering] From 0e3ace36fbb1afb8153dc9ee6bb3a75c6e2b9efd Mon Sep 17 00:00:00 2001 From: roschaefer Date: Thu, 14 Nov 2019 22:57:09 +0100 Subject: [PATCH 3/4] Remove global filters for disabled/deleted I think there is no use case for it and it looks to me like sth. you shouldn't be able to query for. --- .../src/middleware/permissionsMiddleware.js | 18 +---- .../softDelete/softDeleteMiddleware.js | 4 +- .../softDelete/softDeleteMiddleware.spec.js | 70 ------------------- 3 files changed, 3 insertions(+), 89 deletions(-) diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index d312bc112..b0d07c8ec 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -41,20 +41,6 @@ const isMySocialMedia = rule({ return socialMedia.ownedBy.node.id === user.id }) -/* TODO: decide if we want to remove this check: the check - * `onlyEnabledContent` throws authorization errors only if you have - * arguments for `disabled` or `deleted` assuming these are filter - * parameters. Soft-delete middleware obfuscates data on its way out - * anyways. Furthermore, `neo4j-graphql-js` offers many ways to filter for - * data so I believe, this is not a good check anyways. - */ -const onlyEnabledContent = rule({ - cache: 'strict', -})(async (parent, args, ctx, info) => { - const { disabled, deleted } = args - return !(disabled || deleted) -}) - const invitationLimitReached = rule({ cache: 'no_cache', })(async (parent, args, { user, driver }) => { @@ -125,7 +111,8 @@ const permissions = shield( reports: isModerator, statistics: allow, currentUser: allow, - Post: or(onlyEnabledContent, isModerator), + Post: allow, + profilePagePosts: allow, Comment: allow, User: or(noEmailFilter, isAdmin), isLoggedIn: allow, @@ -134,7 +121,6 @@ const permissions = shield( PostsEmotionsByCurrentUser: isAuthenticated, blockedUsers: isAuthenticated, notifications: isAuthenticated, - profilePagePosts: or(onlyEnabledContent, isModerator), Donations: isAuthenticated, }, Mutation: { diff --git a/backend/src/middleware/softDelete/softDeleteMiddleware.js b/backend/src/middleware/softDelete/softDeleteMiddleware.js index 3360d4085..8be8c3d39 100644 --- a/backend/src/middleware/softDelete/softDeleteMiddleware.js +++ b/backend/src/middleware/softDelete/softDeleteMiddleware.js @@ -3,9 +3,7 @@ const isModerator = ({ user }) => { } const setDefaultFilters = (resolve, root, args, context, info) => { - if (typeof args.deleted !== 'boolean') { - args.deleted = false - } + args.deleted = false if (!isModerator(context)) { args.disabled = false diff --git a/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js b/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js index 5b04abebd..fa942f5c4 100644 --- a/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js +++ b/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js @@ -341,76 +341,6 @@ describe('softDeleteMiddleware', () => { }) }) }) - - describe('filter (deleted: true)', () => { - beforeEach(() => { - graphqlQuery = gql` - { - Post(deleted: true) { - title - } - } - ` - }) - - describe('as user', () => { - beforeEach(async () => { - authenticatedUser = await user.toJson() - }) - - it('throws authorisation error', async () => { - const { data, errors } = await action() - expect(data).toEqual({ Post: null }) - expect(errors[0]).toHaveProperty('message', 'Not Authorised!') - }) - }) - - describe('as moderator', () => { - beforeEach(async () => { - authenticatedUser = await moderator.toJson() - }) - - it('does not show deleted posts', async () => { - const expected = { data: { Post: [{ title: 'UNAVAILABLE' }] } } - await expect(action()).resolves.toMatchObject(expected) - }) - }) - }) - - describe('filter (disabled: true)', () => { - beforeEach(() => { - graphqlQuery = gql` - { - Post(disabled: true) { - title - } - } - ` - }) - - describe('as user', () => { - beforeEach(async () => { - authenticatedUser = await user.toJson() - }) - - it('throws authorisation error', async () => { - const { data, errors } = await action() - expect(data).toEqual({ Post: null }) - expect(errors[0]).toHaveProperty('message', 'Not Authorised!') - }) - }) - - describe('as moderator', () => { - beforeEach(async () => { - authenticatedUser = await moderator.toJson() - }) - - it('shows disabled posts', async () => { - const expected = { data: { Post: [{ title: 'Disabled post' }] } } - await expect(action()).resolves.toMatchObject(expected) - }) - }) - }) }) }) }) From fe48c0f4f2e05df15c9f05aa93efde24e080eb37 Mon Sep 17 00:00:00 2001 From: roschaefer Date: Fri, 15 Nov 2019 00:30:30 +0100 Subject: [PATCH 4/4] Revert the taggedCount and postCount We need the order input types for our admin features. This is a potential DOS vulnerability: Ordering the tags by taggedCount might lead to very expensive cypher statements. --- backend/src/schema/types/type/Category.gql | 2 ++ backend/src/schema/types/type/Tag.gql | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/backend/src/schema/types/type/Category.gql b/backend/src/schema/types/type/Category.gql index 9805344d1..39efeff9d 100644 --- a/backend/src/schema/types/type/Category.gql +++ b/backend/src/schema/types/type/Category.gql @@ -11,6 +11,8 @@ enum _CategoryOrdering { createdAt_desc updatedAt_asc updatedAt_desc + postCount_asc + postCount_desc } type Category { diff --git a/backend/src/schema/types/type/Tag.gql b/backend/src/schema/types/type/Tag.gql index 8da899027..41a772e4d 100644 --- a/backend/src/schema/types/type/Tag.gql +++ b/backend/src/schema/types/type/Tag.gql @@ -27,6 +27,10 @@ type Tag { enum _TagOrdering { id_asc id_desc + taggedCount_asc + taggedCount_desc + taggedCountUnique_asc + taggedCountUnique_desc } type Query {