From 5d5574b1b5f7587139e3f822b62f388483379ab2 Mon Sep 17 00:00:00 2001 From: mattwr18 Date: Thu, 9 Jan 2020 16:07:25 +0100 Subject: [PATCH 01/10] Blocked users cannot comment on my posts --- .../src/middleware/permissionsMiddleware.js | 1 + backend/src/schema/resolvers/posts.js | 2 +- backend/src/schema/resolvers/users.js | 23 +++++++++ backend/src/schema/types/type/User.gql | 7 +-- webapp/components/Comment/Comment.vue | 6 +-- webapp/graphql/User.js | 7 +++ webapp/locales/en.json | 4 +- webapp/pages/post/_id/_slug/index.vue | 48 +++++++++++++++---- 8 files changed, 80 insertions(+), 18 deletions(-) diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 3b42ae7fe..12a557232 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -102,6 +102,7 @@ export default shield( blockedUsers: isAuthenticated, notifications: isAuthenticated, Donations: isAuthenticated, + blockedByPostAuthor: isAuthenticated, }, Mutation: { '*': deny, diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index 47223faea..619b1de25 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -42,7 +42,7 @@ const maintainPinnedPosts = params => { export default { Query: { Post: async (object, params, context, resolveInfo) => { - params = await filterForBlockedUsers(params, context) + // params = await filterForBlockedUsers(params, context) params = await maintainPinnedPosts(params) return neo4jgraphql(object, params, context, resolveInfo) }, diff --git a/backend/src/schema/resolvers/users.js b/backend/src/schema/resolvers/users.js index 0b3f13631..c2600ab24 100644 --- a/backend/src/schema/resolvers/users.js +++ b/backend/src/schema/resolvers/users.js @@ -48,6 +48,29 @@ export default { throw new UserInputError(e.message) } }, + blockedByPostAuthor: async (_parent, params, context, _resolveInfo) => { + const { postAuthorId } = params + const { user, driver } = context + const session = driver.session() + const readTxResultPromise = session.readTransaction(async transaction => { + const blockedByPostAuthorTransactionResponse = await transaction.run( + ` + MATCH (currentUser:User {id: $currentUserId})<-[relationship:BLOCKED]-(postAuthor:User {id: $postAuthorId}) + RETURN COUNT(relationship) >= 1 as blockedByPostAuthor + `, + { postAuthorId, currentUserId: user.id }, + ) + return blockedByPostAuthorTransactionResponse.records.map(record => + record.get('blockedByPostAuthor'), + ) + }) + try { + const [blockedByPostAuthor] = await readTxResultPromise + return blockedByPostAuthor + } finally { + session.close() + } + }, User: async (object, args, context, resolveInfo) => { const { email } = args if (email) { diff --git a/backend/src/schema/types/type/User.gql b/backend/src/schema/types/type/User.gql index 243f45322..17ee2a733 100644 --- a/backend/src/schema/types/type/User.gql +++ b/backend/src/schema/types/type/User.gql @@ -68,10 +68,11 @@ type User { RETURN COUNT(u) >= 1 """ ) + isBlocked: Boolean! @cypher( statement: """ - MATCH (this)<-[: BLOCKED]-(u: User { id: $cypherParams.currentUserId}) - RETURN COUNT(u) >= 1 + MATCH (this)<-[:BLOCKED]-(user:User {id: $cypherParams.currentUserId}) + RETURN COUNT(user) >= 1 """ ) @@ -159,7 +160,7 @@ type Query { orderBy: [_UserOrdering] filter: _UserFilter ): [User] - + blockedByPostAuthor(postAuthorId: ID!): Boolean! blockedUsers: [User] currentUser: User } diff --git a/webapp/components/Comment/Comment.vue b/webapp/components/Comment/Comment.vue index cc7f815b9..f776aa413 100644 --- a/webapp/components/Comment/Comment.vue +++ b/webapp/components/Comment/Comment.vue @@ -33,7 +33,7 @@
- '' }, diff --git a/webapp/graphql/User.js b/webapp/graphql/User.js index 4ed832ad3..fa4b47423 100644 --- a/webapp/graphql/User.js +++ b/webapp/graphql/User.js @@ -216,3 +216,10 @@ export const checkSlugAvailableQuery = gql` } } ` +export const blockedByPostAuthor = () => { + return gql` + query($postAuthorId: ID!) { + blockedByPostAuthor(postAuthorId: $postAuthorId) + } + ` +} diff --git a/webapp/locales/en.json b/webapp/locales/en.json index 6d8401e21..7d970998d 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -317,7 +317,9 @@ "their-perspective": "Vice versa: The blocked person will also no longer see your posts in their news feed.", "search": "Posts of blocked people disappear from your search results.", "notifications": "Blocked users will no longer receive notifications if they are mentioned in your posts.", - "closing": "This should be sufficient for now so that blocked users can no longer bother you." + "closing": "This should be sufficient for now so that blocked users can no longer bother you.", + "commenting-disabled": "Commenting is not possible at this time on this post.", + "commenting-explanation": "This can happen for several reasons, please see " }, "columns": { "name": "Name", diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index a94bf7b2d..bdfa13cf2 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -89,7 +89,19 @@ @toggleNewCommentForm="toggleNewCommentForm" /> - + + + + {{ $t('settings.blocked-users.explanation.commenting-disabled') }} +
+ {{ $t('settings.blocked-users.explanation.commenting-explanation') }} + https://human-connection.org +
+
@@ -102,12 +114,13 @@ import HcHashtag from '~/components/Hashtag/Hashtag' import ContentMenu from '~/components/ContentMenu/ContentMenu' import HcUser from '~/components/User/User' import HcShoutButton from '~/components/ShoutButton.vue' -import HcCommentForm from '~/components/CommentForm/CommentForm' +import CommentForm from '~/components/CommentForm/CommentForm' import HcCommentList from '~/components/CommentList/CommentList' import { postMenuModalsData, deletePostMutation } from '~/components/utils/PostHelpers' import PostQuery from '~/graphql/PostQuery' import HcEmotions from '~/components/Emotions/Emotions' import PostMutations from '~/graphql/PostMutations' +import { blockedByPostAuthor } from '~/graphql/User' export default { name: 'PostSlug', @@ -121,7 +134,7 @@ export default { HcUser, HcShoutButton, ContentMenu, - HcCommentForm, + CommentForm, HcCommentList, HcEmotions, ContentViewer, @@ -138,15 +151,10 @@ export default { title: 'loading', showNewCommentForm: true, blurred: false, + blocked: null, + postAuthor: null, } }, - watch: { - Post(post) { - this.post = post[0] || {} - this.title = this.post.title - this.blurred = this.post.imageBlurred - }, - }, mounted() { setTimeout(() => { // NOTE: quick fix for jumping flexbox implementation @@ -215,6 +223,26 @@ export default { id: this.$route.params.id, } }, + update({ Post }) { + this.post = Post[0] || {} + this.title = this.post.title + this.blurred = this.post.imageBlurred + this.postAuthor = this.post.author + }, + fetchPolicy: 'cache-and-network', + }, + blockedByPostAuthor: { + query() { + return blockedByPostAuthor() + }, + variables() { + return { + postAuthorId: this.postAuthor ? this.postAuthor.id : this.$store.getters['auth/user'].id, + } + }, + update({ blockedByPostAuthor }) { + this.blocked = blockedByPostAuthor + }, fetchPolicy: 'cache-and-network', }, }, From c7ee90e9800903402ea5db261112f7655b932ab0 Mon Sep 17 00:00:00 2001 From: mattwr18 Date: Tue, 21 Jan 2020 18:50:46 +0100 Subject: [PATCH 02/10] Follow @roschaefer PR suggestions - As blocking is now reciprocal, we do not need another query, we can use neo4j-graphql-js magic to query for a BLOCKED relationship between the postAuthor and the currentUser --- .../src/middleware/permissionsMiddleware.js | 1 - backend/src/schema/resolvers/users.js | 23 ------------------- backend/src/schema/types/type/User.gql | 3 +-- webapp/graphql/PostQuery.js | 1 + webapp/graphql/User.js | 7 ------ webapp/pages/post/_id/_slug/index.vue | 17 +------------- 6 files changed, 3 insertions(+), 49 deletions(-) diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 12a557232..3b42ae7fe 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -102,7 +102,6 @@ export default shield( blockedUsers: isAuthenticated, notifications: isAuthenticated, Donations: isAuthenticated, - blockedByPostAuthor: isAuthenticated, }, Mutation: { '*': deny, diff --git a/backend/src/schema/resolvers/users.js b/backend/src/schema/resolvers/users.js index c2600ab24..0b3f13631 100644 --- a/backend/src/schema/resolvers/users.js +++ b/backend/src/schema/resolvers/users.js @@ -48,29 +48,6 @@ export default { throw new UserInputError(e.message) } }, - blockedByPostAuthor: async (_parent, params, context, _resolveInfo) => { - const { postAuthorId } = params - const { user, driver } = context - const session = driver.session() - const readTxResultPromise = session.readTransaction(async transaction => { - const blockedByPostAuthorTransactionResponse = await transaction.run( - ` - MATCH (currentUser:User {id: $currentUserId})<-[relationship:BLOCKED]-(postAuthor:User {id: $postAuthorId}) - RETURN COUNT(relationship) >= 1 as blockedByPostAuthor - `, - { postAuthorId, currentUserId: user.id }, - ) - return blockedByPostAuthorTransactionResponse.records.map(record => - record.get('blockedByPostAuthor'), - ) - }) - try { - const [blockedByPostAuthor] = await readTxResultPromise - return blockedByPostAuthor - } finally { - session.close() - } - }, User: async (object, args, context, resolveInfo) => { const { email } = args if (email) { diff --git a/backend/src/schema/types/type/User.gql b/backend/src/schema/types/type/User.gql index 17ee2a733..715a1f3e1 100644 --- a/backend/src/schema/types/type/User.gql +++ b/backend/src/schema/types/type/User.gql @@ -71,7 +71,7 @@ type User { isBlocked: Boolean! @cypher( statement: """ - MATCH (this)<-[:BLOCKED]-(user:User {id: $cypherParams.currentUserId}) + MATCH (this)-[:BLOCKED]-(user:User {id: $cypherParams.currentUserId}) RETURN COUNT(user) >= 1 """ ) @@ -160,7 +160,6 @@ type Query { orderBy: [_UserOrdering] filter: _UserFilter ): [User] - blockedByPostAuthor(postAuthorId: ID!): Boolean! blockedUsers: [User] currentUser: User } diff --git a/webapp/graphql/PostQuery.js b/webapp/graphql/PostQuery.js index c59c894a5..a3ac8345a 100644 --- a/webapp/graphql/PostQuery.js +++ b/webapp/graphql/PostQuery.js @@ -29,6 +29,7 @@ export default i18n => { ...user ...userCounts ...locationAndBadges + isBlocked } comments(orderBy: createdAt_asc) { ...comment diff --git a/webapp/graphql/User.js b/webapp/graphql/User.js index fa4b47423..4ed832ad3 100644 --- a/webapp/graphql/User.js +++ b/webapp/graphql/User.js @@ -216,10 +216,3 @@ export const checkSlugAvailableQuery = gql` } } ` -export const blockedByPostAuthor = () => { - return gql` - query($postAuthorId: ID!) { - blockedByPostAuthor(postAuthorId: $postAuthorId) - } - ` -} diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index bdfa13cf2..41e9f4503 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -90,7 +90,7 @@ /> @@ -120,7 +120,6 @@ import { postMenuModalsData, deletePostMutation } from '~/components/utils/PostH import PostQuery from '~/graphql/PostQuery' import HcEmotions from '~/components/Emotions/Emotions' import PostMutations from '~/graphql/PostMutations' -import { blockedByPostAuthor } from '~/graphql/User' export default { name: 'PostSlug', @@ -231,20 +230,6 @@ export default { }, fetchPolicy: 'cache-and-network', }, - blockedByPostAuthor: { - query() { - return blockedByPostAuthor() - }, - variables() { - return { - postAuthorId: this.postAuthor ? this.postAuthor.id : this.$store.getters['auth/user'].id, - } - }, - update({ blockedByPostAuthor }) { - this.blocked = blockedByPostAuthor - }, - fetchPolicy: 'cache-and-network', - }, }, } From bcae52180e3ff5ae7ecf9de31800aa691e47a648 Mon Sep 17 00:00:00 2001 From: mattwr18 Date: Tue, 21 Jan 2020 19:28:03 +0100 Subject: [PATCH 03/10] Remove filter on posts for BLOCKED --- backend/src/schema/resolvers/posts.js | 29 +-------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index 619b1de25..72af86b4f 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -1,34 +1,10 @@ import uuid from 'uuid/v4' import { neo4jgraphql } from 'neo4j-graphql-js' import fileUpload from './fileUpload' -import { getBlockedUsers, getBlockedByUsers } from './users.js' -import { mergeWith, isArray, isEmpty } from 'lodash' +import { isEmpty } from 'lodash' import { UserInputError } from 'apollo-server' import Resolver from './helpers/Resolver' -const filterForBlockedUsers = async (params, context) => { - if (!context.user) return params - const [blockedUsers, blockedByUsers] = await Promise.all([ - getBlockedUsers(context), - getBlockedByUsers(context), - ]) - const badIds = [...blockedByUsers.map(b => b.id), ...blockedUsers.map(b => b.id)] - if (!badIds.length) return params - - params.filter = mergeWith( - params.filter, - { - author_not: { id_in: badIds }, - }, - (objValue, srcValue) => { - if (isArray(objValue)) { - return objValue.concat(srcValue) - } - }, - ) - return params -} - const maintainPinnedPosts = params => { const pinnedPostFilter = { pinned: true } if (isEmpty(params.filter)) { @@ -42,16 +18,13 @@ const maintainPinnedPosts = params => { export default { Query: { Post: async (object, params, context, resolveInfo) => { - // params = await filterForBlockedUsers(params, context) params = await maintainPinnedPosts(params) return neo4jgraphql(object, params, context, resolveInfo) }, findPosts: async (object, params, context, resolveInfo) => { - params = await filterForBlockedUsers(params, context) return neo4jgraphql(object, params, context, resolveInfo) }, profilePagePosts: async (object, params, context, resolveInfo) => { - params = await filterForBlockedUsers(params, context) return neo4jgraphql(object, params, context, resolveInfo) }, PostsEmotionsCountByEmotion: async (object, params, context, resolveInfo) => { From 2df4e463f89b988eb5e37f55ab1eedd688423909 Mon Sep 17 00:00:00 2001 From: mattwr18 Date: Tue, 21 Jan 2020 19:28:19 +0100 Subject: [PATCH 04/10] Update/Add translations for placeholder message - @alina-beck, I had a look at the Placeholder component and it's quite simple, but I guess migrating that is a separate PR, but I don't know aobut adding more ds-placeholders, do you have some design ideas on what could look better? --- webapp/locales/de.json | 13 +++++++------ webapp/locales/en.json | 9 ++++----- webapp/pages/post/_id/_slug/index.vue | 14 ++++++-------- webapp/pages/settings/blocked-users.vue | 3 --- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/webapp/locales/de.json b/webapp/locales/de.json index 1417d3a51..03fcc0f74 100644 --- a/webapp/locales/de.json +++ b/webapp/locales/de.json @@ -149,11 +149,12 @@ "name": "Blockierte Benutzer", "explanation": { "intro": "Wenn ein anderer Benutzer von dir blockiert wurde, dann passiert folgendes:", - "your-perspective": "In deiner Beitragsübersicht tauchen keine Beiträge der blockierten Person mehr auf.", - "their-perspective": "Umgekehrt das gleiche: Die blockierte Person sieht deine Beiträge auch nicht mehr in ihrer Übersicht.", - "search": "Die Beiträge von blockierten Personen verschwinden aus deinen Suchergebnissen.", - "notifications": "Von dir blockierte Personen erhalten keine Benachrichtigungen mehr, wenn sie in deinen Beiträgen erwähnt werden.", - "closing": "Das sollte fürs Erste genügen, damit blockierte Benutzer dich nicht mehr länger belästigen können." + "your-perspective": "Sie werden nicht mehr in der Lage sein, mit ihren Beiträgen zu interagieren.", + "their-perspective": "Umgekehrt das gleiche: Die blockierte Person kann auch nicht mehr mit Ihren Beiträgen interagieren.", + "notifications": "Gesperrte Benutzer erhalten keine Benachrichtigungen mehr, wenn sie sich gegenseitig erwähnen.", + "closing": "Das sollte fürs Erste genügen, damit blockierte Benutzer dich nicht mehr länger belästigen können.", + "commenting-disabled": "Ein Kommentar zu diesem Beitrag ist zur Zeit nicht möglich.", + "commenting-explanation": "Dies kann aus verschiedenen Gründen geschehen, siehe " }, "columns": { "name": "Name", @@ -485,7 +486,7 @@ }, "teaserImage": { "cropperConfirm": "Bestätigen" - }, + }, "inappropriatePicture" : "Dieses Bild kann für einige Menschen unangemessen sein.", "inappropriatePictureText" : "Wann soll ein Foto versteckt werden" }, diff --git a/webapp/locales/en.json b/webapp/locales/en.json index 7d970998d..330497a3c 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -313,13 +313,12 @@ "name": "Blocked users", "explanation": { "intro": "If another user has been blocked by you, this is what happens:", - "your-perspective": "The blocked person's posts will no longer appear in your news feed.", - "their-perspective": "Vice versa: The blocked person will also no longer see your posts in their news feed.", - "search": "Posts of blocked people disappear from your search results.", - "notifications": "Blocked users will no longer receive notifications if they are mentioned in your posts.", + "your-perspective": "You will no longer be able to interact with their contributions.", + "their-perspective": "Vice versa: The blocked person will also no longer be able to interact with your contributions.", + "notifications": "Blocked users will no longer receive notifications if they mention each other.", "closing": "This should be sufficient for now so that blocked users can no longer bother you.", "commenting-disabled": "Commenting is not possible at this time on this post.", - "commenting-explanation": "This can happen for several reasons, please see " + "commenting-explanation": "This can happen for several reasons, please see our " }, "columns": { "name": "Name", diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index 41e9f4503..f0757e5a3 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -94,14 +94,12 @@ :post="post" @createComment="createComment" /> - - - {{ $t('settings.blocked-users.explanation.commenting-disabled') }} -
- {{ $t('settings.blocked-users.explanation.commenting-explanation') }} - https://human-connection.org -
-
+ + {{ $t('settings.blocked-users.explanation.commenting-disabled') }} +
+ {{ $t('settings.blocked-users.explanation.commenting-explanation') }} + FAQ +
diff --git a/webapp/pages/settings/blocked-users.vue b/webapp/pages/settings/blocked-users.vue index acbd253aa..db7dd9f93 100644 --- a/webapp/pages/settings/blocked-users.vue +++ b/webapp/pages/settings/blocked-users.vue @@ -12,9 +12,6 @@ {{ $t('settings.blocked-users.explanation.their-perspective') }} - - {{ $t('settings.blocked-users.explanation.search') }} - {{ $t('settings.blocked-users.explanation.notifications') }} From e639358557461dfd8c32be4a6d03cb0e879a5014 Mon Sep 17 00:00:00 2001 From: mattwr18 Date: Tue, 21 Jan 2020 21:16:42 +0100 Subject: [PATCH 05/10] Test drive to get the functionality how we'd like --- backend/src/schema/resolvers/searches.js | 2 +- backend/src/schema/resolvers/users.js | 22 +++++++++ cypress/integration/common/steps.js | 32 ++++++++++++- .../user_profile/BlockUser.feature | 48 +++++++++++++++++++ .../user_profile/mute-users/Mute.feature | 5 +- webapp/components/ContentMenu/ContentMenu.vue | 17 +++++++ webapp/locales/en.json | 4 +- webapp/pages/profile/_id/_slug.vue | 23 ++++++++- 8 files changed, 145 insertions(+), 8 deletions(-) create mode 100644 cypress/integration/user_profile/BlockUser.feature diff --git a/backend/src/schema/resolvers/searches.js b/backend/src/schema/resolvers/searches.js index 5316ccd9a..bfbdd21b1 100644 --- a/backend/src/schema/resolvers/searches.js +++ b/backend/src/schema/resolvers/searches.js @@ -20,7 +20,7 @@ export default { AND NOT ( author.deleted = true OR author.disabled = true OR resource.deleted = true OR resource.disabled = true - OR (:User { id: $thisUserId })-[:BLOCKED]-(author) + OR (:User { id: $thisUserId })-[:MUTED]-(author) ) WITH resource, author, [(resource)<-[:COMMENTS]-(comment:Comment) | comment] as comments, diff --git a/backend/src/schema/resolvers/users.js b/backend/src/schema/resolvers/users.js index dc962dc00..915d8b6f8 100644 --- a/backend/src/schema/resolvers/users.js +++ b/backend/src/schema/resolvers/users.js @@ -23,6 +23,21 @@ export const getMutedUsers = async context => { return mutedUsers } +export const getBlockedUsers = async context => { + const { neode } = context + const userModel = neode.model('User') + let blockedUsers = neode + .query() + .match('user', userModel) + .where('user.id', context.user.id) + .relationship(userModel.relationships().get('blocked')) + .to('blocked', userModel) + .return('blocked') + blockedUsers = await blockedUsers.execute() + blockedUsers = blockedUsers.records.map(r => r.get('blocked').properties) + return blockedUsers +} + export default { Query: { mutedUsers: async (object, args, context, resolveInfo) => { @@ -32,6 +47,13 @@ export default { throw new UserInputError(e.message) } }, + blockedUsers: async (object, args, context, resolveInfo) => { + try { + return getBlockedUsers(context) + } catch (e) { + throw new UserInputError(e.message) + } + }, User: async (object, args, context, resolveInfo) => { const { email } = args if (email) { diff --git a/cypress/integration/common/steps.js b/cypress/integration/common/steps.js index 53b5f7c3d..29f2fa85a 100644 --- a/cypress/integration/common/steps.js +++ b/cypress/integration/common/steps.js @@ -39,7 +39,7 @@ Given("I am logged in", () => { cy.login(loginCredentials); }); -Given("I am logged in as the muted user", () => { +Given("I am logged in as the {string} user", _ => { cy.login({ email: annoyingParams.email, password: '1234' }); }); @@ -123,6 +123,12 @@ When("I visit the {string} page", page => { cy.openPage(page); }); +When("the blocked user visits my post", () => { + cy.logout() + .login({ email: annoyingParams.email, password: annoyingParams.password }) + .openPage('/post/previously-created-post') +}) + Given("I am on the {string} page", page => { cy.openPage(page); }); @@ -485,7 +491,7 @@ Given("I follow the user {string}", name => { }); }); -Given('"Spammy Spammer" wrote a post {string}', title => { +Given('{string} wrote a post {string}', (_, title) => { cy.createCategories("cat21") .factory() .create("Post", { @@ -532,6 +538,20 @@ When("I mute the user {string}", name => { }); }); +When("I block the user {string}", name => { + cy.neode() + .first("User", { + name + }) + .then(blockedUser => { + cy.neode() + .first("User", { + name: narratorParams.name + }) + .relateTo(blockedUser, "blocked"); + }); +}); + When("I log in with:", table => { const [firstRow] = table.hashes(); const { @@ -550,3 +570,11 @@ Then("I see only one post with the title {string}", title => { .should("have.length", 1); cy.get(".main-container").contains(".post-link", title); }); + +Then("they should not see the comment from", () => { + cy.get(".ds-card-footer").children().should('not.have.class', 'comment-form') +}) + +Then("they should see a text explaining commenting is not possible", () => { + cy.get('.ds-placeholder').should('contain', "Commenting is not possible at this time on this post.") +}) \ No newline at end of file diff --git a/cypress/integration/user_profile/BlockUser.feature b/cypress/integration/user_profile/BlockUser.feature new file mode 100644 index 000000000..a04455b53 --- /dev/null +++ b/cypress/integration/user_profile/BlockUser.feature @@ -0,0 +1,48 @@ +Feature: Block a User + As a user + I'd like to have a button to block another user + To prevent him from seeing and interacting with my contributions + + Background: + Given I have a user account + And there is an annoying user called "Harassing User" + And I am logged in + + Scenario: Block a user + Given I am on the profile page of the annoying user + When I click on "Block user" from the content menu in the user info box + And I navigate to my "Blocked users" settings page + Then I can see the following table: + | Avatar | Name | + | | Harassing User | + + Scenario: Blocked user cannot interact with my contributions + Given I block the user "Harassing User" + And I previously created a post + And the blocked user visits my post + Then they should not see the comment from + And they should see a text explaining commenting is not possible + + Scenario: Block a previously followed user + Given I follow the user "Harassing User" + When I visit the profile page of the annoying user + And I click on "Block user" from the content menu in the user info box + And nobody is following the user profile anymore + + Scenario: Posts of blocked users are not filtered from search results + Given "Harassing User" wrote a post "You can still see my posts" + And I block the user "Harassing User" + When I search for "see" + Then I should see the following posts in the select dropdown: + | title | + | You can still see my posts | + + Scenario: Blocked users can still see my posts + Given I previously created a post + And I block the user "Harassing User" + Given I log out + And I am logged in as the "blocked" user + When I search for "previously created" + Then I should see the following posts in the select dropdown: + | title | + | previously created post | diff --git a/cypress/integration/user_profile/mute-users/Mute.feature b/cypress/integration/user_profile/mute-users/Mute.feature index b52faeeaa..cd7d1c827 100644 --- a/cypress/integration/user_profile/mute-users/Mute.feature +++ b/cypress/integration/user_profile/mute-users/Mute.feature @@ -1,8 +1,7 @@ Feature: Mute a User As a user I'd like to have a button to mute another user - To prevent him from seeing and interacting with my contributions and also to avoid seeing his/her posts - + To prevent him from seeing and interacting with my contributions Background: Given I have a user account And there is an annoying user called "Spammy Spammer" @@ -46,7 +45,7 @@ Feature: Mute a User Given I previously created a post And I mute the user "Spammy Spammer" Given I log out - And I am logged in as the muted user + And I am logged in as the "muted" user When I search for "previously created" Then I should see the following posts in the select dropdown: | title | diff --git a/webapp/components/ContentMenu/ContentMenu.vue b/webapp/components/ContentMenu/ContentMenu.vue index a22bc3267..31d90a614 100644 --- a/webapp/components/ContentMenu/ContentMenu.vue +++ b/webapp/components/ContentMenu/ContentMenu.vue @@ -172,6 +172,23 @@ export default { icon: 'user-times', }) } + if (this.resource.isBlocked) { + routes.push({ + label: this.$t(`settings.blocked-users.unblock`), + callback: () => { + this.$emit('unblock', this.resource) + }, + icon: 'user-plus', + }) + } else { + routes.push({ + label: this.$t(`settings.blocked-users.block`), + callback: () => { + this.$emit('block', this.resource) + }, + icon: 'user-times', + }) + } } } diff --git a/webapp/locales/en.json b/webapp/locales/en.json index 2191a91e7..e36214d8a 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -337,7 +337,9 @@ "your-perspective": "You will no longer be able to interact with their contributions.", "their-perspective": "Vice versa: The blocked person will also no longer be able to interact with your contributions.", "notifications": "Blocked users will no longer receive notifications if they mention each other.", - "closing": "This should be sufficient for now so that blocked users can no longer bother you." + "closing": "This should be sufficient for now so that blocked users can no longer bother you.", + "commenting-disabled": "Commenting is not possible at this time on this post.", + "commenting-explanation": "This can happen for several reasons, please see our " }, "columns": { "name": "Name", diff --git a/webapp/pages/profile/_id/_slug.vue b/webapp/pages/profile/_id/_slug.vue index ce220b66b..01190caa2 100644 --- a/webapp/pages/profile/_id/_slug.vue +++ b/webapp/pages/profile/_id/_slug.vue @@ -24,6 +24,8 @@ class="user-content-menu" @mute="muteUser" @unmute="unmuteUser" + @block="blockUser" + @unblock="unblockUser" /> @@ -67,7 +69,7 @@