+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+ {{ post.shoutedCount }}
+
+
+
+ {{ post.commentsCount }}
+
-
-
-
-
-
-
-
-
-
- {{ post.shoutedCount }}
-
-
-
-
- {{ post.commentsCount }}
-
-
-
-
-
+
+
+
+
+
diff --git a/components/ReportModal.vue b/components/ReportModal.vue
new file mode 100644
index 000000000..1ae23fd94
--- /dev/null
+++ b/components/ReportModal.vue
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ cancelLabel }}
+
+
+ {{ confirmLabel }}
+
+
+
+
+
+
+
+
diff --git a/cypress/fixtures/users.json b/cypress/fixtures/users.json
new file mode 100644
index 000000000..339866774
--- /dev/null
+++ b/cypress/fixtures/users.json
@@ -0,0 +1,17 @@
+{
+ "admin": {
+ "email": "admin@example.org",
+ "password": "1234",
+ "name": "Peter Lustig"
+ },
+ "moderator": {
+ "email": "moderator@example.org",
+ "password": "1234",
+ "name": "Bob der Bausmeister"
+ },
+ "user": {
+ "email": "user@example.org",
+ "password": "1234",
+ "name": "Jenny Rostock"
+ }
+}
diff --git a/cypress/integration/04.AboutMeAndLocation.feature b/cypress/integration/04.AboutMeAndLocation.feature
index 83e7046f5..8601f7c80 100644
--- a/cypress/integration/04.AboutMeAndLocation.feature
+++ b/cypress/integration/04.AboutMeAndLocation.feature
@@ -1,4 +1,4 @@
-Feature: About me and and location
+Feature: About me and location
As a user
I would like to add some about me text and a location
So others can get some info about me and my location
diff --git a/cypress/integration/05.ReportContent.feature b/cypress/integration/05.ReportContent.feature
new file mode 100644
index 000000000..fbfdfe8de
--- /dev/null
+++ b/cypress/integration/05.ReportContent.feature
@@ -0,0 +1,59 @@
+Feature: Report and Moderate
+ As a user
+ I would like to report content that viloates the community guidlines
+ So the moderators can take action on it
+
+ As a moderator
+ I would like to see all reported content
+ So I can look into it and decide what to do
+
+ Background:
+ Given we have the following posts in our database:
+ | Author | Title | Content | Slug |
+ | David Irving | The Truth about the Holocaust | It never existed! | the-truth-about-the-holocaust |
+
+ Scenario Outline: Report a post from various pages
+ Given I am logged in with a "user" role
+ And I see David Irving's post on the
+ When I click on "Report Contribution" from the triple dot menu of the post
+ And I confirm the reporting dialog because it is a criminal act under German law:
+ """
+ Do you really want to report the contribution "The Truth about the Holocaust"?
+ """
+ Then I see a success message:
+ """
+ Thanks for reporting!
+ """
+ Examples:
+ | Page |
+ | landing page |
+ | post page |
+
+ Scenario: Report user
+ Given I am logged in with a "user" role
+ And I see David Irving's post on the post page
+ When I click on the author
+ And I click on "Report User" from the triple dot menu in the user info box
+ And I confirm the reporting dialog because he is a holocaust denier:
+ """
+ Do you really want to report the user "David Irving"?
+ """
+ Then I see a success message:
+ """
+ Thanks for reporting!
+ """
+
+ Scenario: Review reported content
+ Given somebody reported the following posts:
+ | Slug |
+ | the-truth-about-the-holocaust |
+ And I am logged in with a "moderator" role
+ When I click on the avatar menu in the top right corner
+ And I click on "Moderation"
+ Then I see all the reported posts including the one from above
+ And each list item links to the post page
+
+ Scenario: Normal user can't see the moderation page
+ Given I am logged in with a "user" role
+ When I click on the avatar menu in the top right corner
+ Then I can't see the moderation menu item
diff --git a/cypress/integration/common/report.js b/cypress/integration/common/report.js
new file mode 100644
index 000000000..3c546f0f5
--- /dev/null
+++ b/cypress/integration/common/report.js
@@ -0,0 +1,141 @@
+import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'
+
+/* global cy */
+
+let lastReportTitle
+let dummyReportedPostTitle = 'Hacker, Freaks und Funktionäre'
+let dummyReportedPostSlug = 'hacker-freaks-und-funktionareder-ccc'
+let dummyAuthorName = 'Jenny Rostock'
+
+const savePostTitle = $post => {
+ return $post
+ .first()
+ .find('.ds-heading')
+ .first()
+ .invoke('text')
+ .then(title => {
+ lastReportTitle = title
+ })
+}
+
+Given("I see David Irving's post on the landing page", page => {
+ cy.openPage('landing')
+})
+
+Given("I see David Irving's post on the post page", page => {
+ cy.visit(`/post/${dummyReportedPostSlug}`)
+ cy.contains(dummyReportedPostTitle) // wait
+})
+
+Given('I am logged in with a {string} role', role => {
+ cy.loginAs(role)
+})
+
+When(
+ 'I click on "Report Contribution" from the triple dot menu of the post',
+ () => {
+ //TODO: match the created post title, not a dummy post title
+ cy.contains('.ds-card', dummyReportedPostTitle)
+ .find('.content-menu-trigger')
+ .first()
+ .click()
+
+ cy.get('.popover .ds-menu-item-link')
+ .contains('Report Contribution')
+ .click()
+ }
+)
+
+When(
+ 'I click on "Report User" from the triple dot menu in the user info box',
+ () => {
+ //TODO: match the created post author, not a dummy author
+ cy.contains('.ds-card', dummyAuthorName)
+ .find('.content-menu-trigger')
+ .first()
+ .click()
+
+ cy.get('.popover .ds-menu-item-link')
+ .contains('Report User')
+ .click()
+ }
+)
+
+When('I click on the author', () => {
+ cy.get('a.author')
+ .first()
+ .click()
+ .wait(200)
+})
+
+When('I report the author', () => {
+ cy.get('.page-name-profile-slug').then(() => {
+ invokeReportOnElement('.ds-card').then(() => {
+ cy.get('button')
+ .contains('Send')
+ .click()
+ })
+ })
+})
+
+When('I click on send in the confirmation dialog', () => {
+ cy.get('button')
+ .contains('Send')
+ .click()
+})
+
+Then('I get a success message', () => {
+ cy.get('.iziToast-message').contains('Thanks')
+})
+
+Then('I see my reported user', () => {
+ cy.get('table').then(() => {
+ cy.get('tbody tr')
+ .first()
+ .contains(lastReportTitle.trim())
+ })
+})
+
+Then(`I can't see the moderation menu item`, () => {
+ cy.get('.avatar-menu-popover')
+ .find('a[href="/settings"]', 'Settings')
+ .should('exist') // OK, the dropdown is actually open
+
+ cy.get('.avatar-menu-popover')
+ .find('a[href="/moderation"]', 'Moderation')
+ .should('not.exist')
+})
+
+When(/^I confirm the reporting dialog .*:$/, () => {
+ //TODO: take message from method argument
+ //TODO: match the right post
+ const message = 'Do you really want to report the'
+ cy.contains(message) // wait for element to become visible
+ //TODO: cy.get('.ds-modal').contains(dummyReportedPostTitle)
+ cy.get('.ds-modal').within(() => {
+ cy.get('button')
+ .contains('Send Report')
+ .click()
+ })
+})
+
+Given('somebody reported the following posts:', table => {
+ table.hashes().forEach(row => {
+ //TODO: calll factory here
+ // const options = Object.assign({}, row, { reported: true })
+ //create('post', options)
+ })
+})
+
+Then('I see all the reported posts including the one from above', () => {
+ //TODO: match the right post
+ cy.get('table tbody').within(() => {
+ cy.contains('tr', dummyReportedPostTitle)
+ })
+})
+
+Then('each list item links to the post page', () => {
+ //TODO: match the right post
+ cy.contains(dummyReportedPostTitle).click()
+ cy.location('pathname').should('contain', '/post')
+})
diff --git a/cypress/integration/common/steps.js b/cypress/integration/common/steps.js
index ee9a364f7..cd4280578 100644
--- a/cypress/integration/common/steps.js
+++ b/cypress/integration/common/steps.js
@@ -1,20 +1,14 @@
import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'
import { getLangByName } from '../../support/helpers'
-import find from 'lodash/find'
+import users from '../../fixtures/users.json'
/* global cy */
-const username = 'Peter Lustig'
-
-const openPage = page => {
- if (page === 'landing') {
- page = ''
- }
- cy.visit(`/${page}`)
-}
-
Given('I am logged in', () => {
- cy.login('admin@example.org', 1234)
+ cy.loginAs('admin')
+})
+Given('I am logged in as {string}', userType => {
+ cy.loginAs(userType)
})
Given('we have a selection of tags and categories as well as posts', () => {
@@ -32,10 +26,11 @@ Given('my user account has the role {string}', role => {
When('I log out', cy.logout)
When('I visit the {string} page', page => {
- openPage(page)
+ cy.openPage(page)
})
+
Given('I am on the {string} page', page => {
- openPage(page)
+ cy.openPage(page)
})
When('I fill in my email and password combination and click submit', () => {
@@ -53,22 +48,22 @@ When('I log out through the menu in the top right corner', () => {
.click()
})
-Then('I can click on my profile picture in the top right corner', () => {
- cy.get('.avatar-menu').click()
- cy.get('.avatar-menu-popover')
-})
-
Then('I can see my name {string} in the dropdown menu', () => {
- cy.get('.avatar-menu-popover').should('contain', username)
+ cy.get('.avatar-menu-popover').should('contain', users.admin.name)
})
Then('I see the login screen again', () => {
cy.location('pathname').should('contain', '/login')
})
+Then('I can click on my profile picture in the top right corner', () => {
+ cy.get('.avatar-menu').click()
+ cy.get('.avatar-menu-popover')
+})
+
Then('I am still logged in', () => {
cy.get('.avatar-menu').click()
- cy.get('.avatar-menu-popover').contains(username)
+ cy.get('.avatar-menu-popover').contains(users.admin.name)
})
When('I select {string} in the language menu', name => {
@@ -93,3 +88,18 @@ When(`I click on {string}`, linkOrButton => {
When('I press {string}', label => {
cy.contains(label).click()
})
+
+Given('we have the following posts in our database:', table => {
+ table.hashes().forEach(row => {
+ //TODO: calll factory here
+ //create('post', row)
+ })
+})
+
+Then('I see a success message:', message => {
+ cy.contains(message)
+})
+
+When('I click on the avatar menu in the top right corner', () => {
+ cy.get('.avatar-menu').click()
+})
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index 77c75c7d5..ebbd6acd1 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -15,6 +15,7 @@
/* globals Cypress cy */
import { getLangByName } from './helpers'
+import users from '../fixtures/users.json'
const switchLang = name => {
cy.get('.locale-menu').click()
@@ -54,11 +55,24 @@ Cypress.Commands.add('login', (email, password) => {
.click()
cy.location('pathname').should('eq', '/') // we're in!
})
+
+Cypress.Commands.add('loginAs', role => {
+ role = role || 'admin'
+ cy.login(users[role].email, users[role].password)
+})
+
Cypress.Commands.add('logout', (email, password) => {
cy.visit(`/logout`)
cy.location('pathname').should('contain', '/login') // we're out
})
+Cypress.Commands.add('openPage', page => {
+ if (page === 'landing') {
+ page = ''
+ }
+ cy.visit(`/${page}`)
+})
+
//
//
// -- This is a child command --
diff --git a/cypress/support/config.js b/cypress/support/config.js
deleted file mode 100644
index af96ad615..000000000
--- a/cypress/support/config.js
+++ /dev/null
@@ -1,16 +0,0 @@
-export default {
- users: {
- admin: {
- email: 'admin@example.org',
- password: 1234
- },
- moderator: {
- email: 'moderator@example.org',
- password: 1234
- },
- user: {
- email: 'user@example.org',
- password: 1234
- }
- }
-}
diff --git a/cypress/support/helpers.js b/cypress/support/helpers.js
index 661682139..1aed57de1 100644
--- a/cypress/support/helpers.js
+++ b/cypress/support/helpers.js
@@ -1,4 +1,3 @@
-
import find from 'lodash/find'
const helpers = {
diff --git a/graphql/ModerationListQuery.js b/graphql/ModerationListQuery.js
new file mode 100644
index 000000000..6126521cc
--- /dev/null
+++ b/graphql/ModerationListQuery.js
@@ -0,0 +1,41 @@
+import gql from 'graphql-tag'
+
+export default app => {
+ return gql(`
+ query {
+ Report(first: 20, orderBy: createdAt_desc) {
+ id
+ description
+ type
+ createdAt
+ reporter {
+ name
+ slug
+ }
+ user {
+ name
+ slug
+ }
+ comment {
+ contentExcerpt
+ author {
+ name
+ slug
+ }
+ post {
+ title
+ slug
+ }
+ }
+ contribution {
+ title
+ slug
+ author {
+ name
+ slug
+ }
+ }
+ }
+ }
+ `)
+}
diff --git a/layouts/default.vue b/layouts/default.vue
index a511dee8a..7283bf308 100644
--- a/layouts/default.vue
+++ b/layouts/default.vue
@@ -92,6 +92,12 @@