diff --git a/backend/package.json b/backend/package.json
index d861f9b6c..edbeabd48 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -11,7 +11,7 @@
"lint": "eslint src --config .eslintrc.js",
"test": "run-s test:jest test:cucumber",
"test:before:server": "cross-env GRAPHQL_URI=http://localhost:4123 GRAPHQL_PORT=4123 yarn run dev 2> /dev/null",
- "test:before:seeder": "cross-env GRAPHQL_URI=http://localhost:4001 GRAPHQL_PORT=4001 DEBUG=true DISABLED_MIDDLEWARES=permissions,activityPub yarn run dev 2> /dev/null",
+ "test:before:seeder": "cross-env GRAPHQL_URI=http://localhost:4001 GRAPHQL_PORT=4001 DISABLED_MIDDLEWARES=permissions,activityPub yarn run dev 2> /dev/null",
"test:jest:cmd": "wait-on tcp:4001 tcp:4123 && jest --forceExit --detectOpenHandles --runInBand",
"test:cucumber:cmd": "wait-on tcp:4001 tcp:4123 && cucumber-js --require-module @babel/register --exit test/",
"test:jest:cmd:debug": "wait-on tcp:4001 tcp:4123 && node --inspect-brk ./node_modules/.bin/jest -i --forceExit --detectOpenHandles --runInBand",
@@ -19,8 +19,8 @@
"test:cucumber": " cross-env CLIENT_URI=http://localhost:4123 run-p --race test:before:* 'test:cucumber:cmd {@}' --",
"test:jest:debug": "run-p --race test:before:* 'test:jest:cmd:debug {@}' --",
"db:script:seed": "wait-on tcp:4001 && babel-node src/seed/seed-db.js",
- "db:reset": "cross-env DEBUG=true babel-node src/seed/reset-db.js",
- "db:seed": "cross-env GRAPHQL_URI=http://localhost:4001 GRAPHQL_PORT=4001 DEBUG=true DISABLED_MIDDLEWARES=permissions run-p --race dev db:script:seed"
+ "db:reset": "cross-env babel-node src/seed/reset-db.js",
+ "db:seed": "cross-env GRAPHQL_URI=http://localhost:4001 GRAPHQL_PORT=4001 DISABLED_MIDDLEWARES=permissions run-p --race dev db:script:seed"
},
"author": "Human Connection gGmbH",
"license": "MIT",
@@ -109,4 +109,4 @@
"prettier": "~1.17.1",
"supertest": "~4.0.2"
}
-}
\ No newline at end of file
+}
diff --git a/backend/src/config/index.js b/backend/src/config/index.js
index 5cc455495..aed6f7c1c 100644
--- a/backend/src/config/index.js
+++ b/backend/src/config/index.js
@@ -23,7 +23,8 @@ export const serverConfigs = {
export const developmentConfigs = {
DEBUG: process.env.NODE_ENV !== 'production' && process.env.DEBUG === 'true',
MOCKS: process.env.MOCKS === 'true',
- DISABLED_MIDDLEWARES: process.env.DISABLED_MIDDLEWARES || '',
+ DISABLED_MIDDLEWARES:
+ (process.env.NODE_ENV !== 'production' && process.env.DISABLED_MIDDLEWARES) || '',
}
export default {
diff --git a/backend/src/middleware/index.js b/backend/src/middleware/index.js
index 754c59bbb..75314abc0 100644
--- a/backend/src/middleware/index.js
+++ b/backend/src/middleware/index.js
@@ -50,7 +50,7 @@ export default schema => {
]
// add permisions middleware at the first position (unless we're seeding)
- if (CONFIG.DEBUG) {
+ if (CONFIG.DISABLED_MIDDLEWARES) {
const disabledMiddlewares = CONFIG.DISABLED_MIDDLEWARES.split(',')
order = order.filter(key => {
return !disabledMiddlewares.includes(key)
diff --git a/backend/src/seed/reset-db.js b/backend/src/seed/reset-db.js
index 5f4319f73..125d135d8 100644
--- a/backend/src/seed/reset-db.js
+++ b/backend/src/seed/reset-db.js
@@ -1,8 +1,7 @@
import { cleanDatabase } from './factories'
-import CONFIG from './../config'
-if (!CONFIG.DEBUG) {
- throw new Error(`YOU CAN'T CLEAN THE DATABASE WITH DEBUG=${CONFIG.DEBUG}`)
+if (process.env.NODE_ENV === 'production') {
+ throw new Error(`You cannot clean the database in production environment!`)
}
;(async function() {
diff --git a/cypress/integration/common/post.js b/cypress/integration/common/post.js
index f6a1bbedd..814159a34 100644
--- a/cypress/integration/common/post.js
+++ b/cypress/integration/common/post.js
@@ -1,25 +1,28 @@
-import { When, Then } from 'cypress-cucumber-preprocessor/steps'
+import { When, Then } from "cypress-cucumber-preprocessor/steps";
-const narratorAvatar = 'https://s3.amazonaws.com/uifaces/faces/twitter/nerrsoft/128.jpg'
+const narratorAvatar =
+ "https://s3.amazonaws.com/uifaces/faces/twitter/nerrsoft/128.jpg";
-Then('I click on the {string} button', text => {
- cy.get('button').contains(text).click()
-})
+Then("I click on the {string} button", text => {
+ cy.get("button")
+ .contains(text)
+ .click();
+});
-Then('my comment should be successfully created', () => {
- cy.get('.iziToast-message')
- .contains('Comment Submitted')
-})
+Then("my comment should be successfully created", () => {
+ cy.get(".iziToast-message").contains("Comment Submitted");
+});
-Then('I should see my comment', () => {
- cy.get('div.comment p')
- .should('contain', 'Human Connection rocks')
- .get('.ds-avatar img')
- .should('have.attr', 'src')
- .and('contain', narratorAvatar)
-})
+Then("I should see my comment", () => {
+ cy.get("div.comment p")
+ .should("contain", "Human Connection rocks")
+ .get(".ds-avatar img")
+ .should("have.attr", "src")
+ .and("contain", narratorAvatar)
+ .get("div p.ds-text span")
+ .should("contain", "today at");
+});
-Then('the editor should be cleared', () => {
- cy.get('.ProseMirror p')
- .should('have.class', 'is-empty')
-})
+Then("the editor should be cleared", () => {
+ cy.get(".ProseMirror p").should("have.class", "is-empty");
+});
diff --git a/webapp/components/Comment.vue b/webapp/components/Comment.vue
index 862b95545..4796dd783 100644
--- a/webapp/components/Comment.vue
+++ b/webapp/components/Comment.vue
@@ -7,7 +7,7 @@
-
+
{
- this.openModal('disable')
- },
- icon: 'eye-slash',
- })
+ if (!this.resource.disabled) {
+ routes.push({
+ name: this.$t(`disable.${this.resourceType}.title`),
+ callback: () => {
+ this.openModal('disable')
+ },
+ icon: 'eye-slash',
+ })
+ } else {
+ routes.push({
+ name: this.$t(`release.${this.resourceType}.title`),
+ callback: () => {
+ this.openModal('release', this.resource.id)
+ },
+ icon: 'eye',
+ })
+ }
}
if (this.isOwner && this.resourceType === 'user') {
diff --git a/webapp/components/Modal.vue b/webapp/components/Modal.vue
index efe1b8ab6..317b5007a 100644
--- a/webapp/components/Modal.vue
+++ b/webapp/components/Modal.vue
@@ -9,6 +9,13 @@
:callbacks="data.callbacks"
@close="close"
/>
+
import DeleteModal from '~/components/Modal/DeleteModal'
import DisableModal from '~/components/Modal/DisableModal'
+import ReleaseModal from '~/components/ReleaseModal/ReleaseModal.vue'
import ReportModal from '~/components/Modal/ReportModal'
import { mapGetters } from 'vuex'
@@ -38,6 +46,7 @@ export default {
name: 'Modal',
components: {
DisableModal,
+ ReleaseModal,
ReportModal,
DeleteModal,
},
diff --git a/webapp/components/Modal/DisableModal.spec.js b/webapp/components/Modal/DisableModal.spec.js
index 02ae3fa5d..87484f6bf 100644
--- a/webapp/components/Modal/DisableModal.spec.js
+++ b/webapp/components/Modal/DisableModal.spec.js
@@ -33,6 +33,9 @@ describe('DisableModal.vue', () => {
$apollo: {
mutate: jest.fn().mockResolvedValue(),
},
+ location: {
+ reload: jest.fn(),
+ },
}
})
diff --git a/webapp/components/Modal/DisableModal.vue b/webapp/components/Modal/DisableModal.vue
index 690dcbf70..988ecc8af 100644
--- a/webapp/components/Modal/DisableModal.vue
+++ b/webapp/components/Modal/DisableModal.vue
@@ -4,9 +4,7 @@
-
- {{ $t('disable.cancel') }}
-
+ {{ $t('disable.cancel') }}
{{ $t('disable.submit') }}
@@ -70,6 +68,9 @@ export default {
setTimeout(() => {
this.$emit('close')
}, 1000)
+ setTimeout(() => {
+ location.reload()
+ }, 250)
} catch (err) {
this.$toast.error(err.message)
}
diff --git a/webapp/components/ReleaseModal/ReleaseModal.spec.js b/webapp/components/ReleaseModal/ReleaseModal.spec.js
new file mode 100644
index 000000000..766d981f8
--- /dev/null
+++ b/webapp/components/ReleaseModal/ReleaseModal.spec.js
@@ -0,0 +1,175 @@
+import { shallowMount, mount, createLocalVue } from '@vue/test-utils'
+import ReleaseModal from './ReleaseModal.vue'
+import Styleguide from '@human-connection/styleguide'
+
+const localVue = createLocalVue()
+
+localVue.use(Styleguide)
+
+describe('ReleaseModal.vue', () => {
+ let mocks
+ let propsData
+ let wrapper
+ let Wrapper
+
+ beforeEach(() => {
+ propsData = {
+ type: 'contribution',
+ name: 'blah',
+ id: 'c42',
+ }
+ mocks = {
+ $filters: {
+ truncate: a => a,
+ },
+ $toast: {
+ success: () => {},
+ error: () => {},
+ },
+ $t: jest.fn(),
+ $apollo: {
+ mutate: jest.fn().mockResolvedValue(),
+ },
+ location: {
+ reload: jest.fn(),
+ },
+ }
+ })
+
+ describe('shallowMount', () => {
+ Wrapper = () => {
+ return shallowMount(ReleaseModal, {
+ propsData,
+ mocks,
+ localVue,
+ })
+ }
+
+ describe('given a user', () => {
+ beforeEach(() => {
+ propsData = {
+ type: 'user',
+ id: 'u2',
+ name: 'Bob Ross',
+ }
+ })
+
+ it('mentions user name', () => {
+ Wrapper()
+ const calls = mocks.$t.mock.calls
+ const expected = [
+ [
+ 'release.user.message',
+ {
+ name: 'Bob Ross',
+ },
+ ],
+ ]
+ expect(calls).toEqual(expect.arrayContaining(expected))
+ })
+ })
+
+ describe('given a contribution', () => {
+ beforeEach(() => {
+ propsData = {
+ type: 'contribution',
+ id: 'c3',
+ name: 'This is some post title.',
+ }
+ })
+
+ it('mentions contribution title', () => {
+ Wrapper()
+ const calls = mocks.$t.mock.calls
+ const expected = [
+ [
+ 'release.contribution.message',
+ {
+ name: 'This is some post title.',
+ },
+ ],
+ ]
+ expect(calls).toEqual(expect.arrayContaining(expected))
+ })
+ })
+ })
+
+ describe('mount', () => {
+ Wrapper = () => {
+ return mount(ReleaseModal, {
+ propsData,
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(jest.useFakeTimers)
+
+ describe('given id', () => {
+ beforeEach(() => {
+ propsData = {
+ type: 'user',
+ id: 'u4711',
+ }
+ })
+
+ describe('click cancel button', () => {
+ beforeEach(() => {
+ wrapper = Wrapper()
+ wrapper.find('button.cancel').trigger('click')
+ })
+
+ it('does not emit "close" yet', () => {
+ expect(wrapper.emitted().close).toBeFalsy()
+ })
+
+ it('fades away', () => {
+ expect(wrapper.vm.isOpen).toBe(false)
+ })
+
+ describe('after timeout', () => {
+ beforeEach(jest.runAllTimers)
+
+ it('does not call mutation', () => {
+ expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
+ })
+
+ it('emits close', () => {
+ expect(wrapper.emitted().close).toBeTruthy()
+ })
+ })
+ })
+
+ describe('click confirm button', () => {
+ beforeEach(() => {
+ wrapper = Wrapper()
+ wrapper.find('button.confirm').trigger('click')
+ })
+
+ it('calls mutation', () => {
+ expect(mocks.$apollo.mutate).toHaveBeenCalled()
+ })
+
+ it('passes id to mutation', () => {
+ const calls = mocks.$apollo.mutate.mock.calls
+ const [[{ variables }]] = calls
+ expect(variables).toEqual({
+ id: 'u4711',
+ })
+ })
+
+ it('fades away', () => {
+ expect(wrapper.vm.isOpen).toBe(false)
+ })
+
+ describe('after timeout', () => {
+ beforeEach(jest.runAllTimers)
+
+ it('emits close', () => {
+ expect(wrapper.emitted().close).toBeTruthy()
+ })
+ })
+ })
+ })
+ })
+})
diff --git a/webapp/components/ReleaseModal/ReleaseModal.vue b/webapp/components/ReleaseModal/ReleaseModal.vue
new file mode 100644
index 000000000..f414d4328
--- /dev/null
+++ b/webapp/components/ReleaseModal/ReleaseModal.vue
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+ {{ $t('release.cancel') }}
+
+
+ {{ $t('release.submit') }}
+
+
+
+
+
+
diff --git a/webapp/locales/de.json b/webapp/locales/de.json
index 8b20f763f..fb33e2fd8 100644
--- a/webapp/locales/de.json
+++ b/webapp/locales/de.json
@@ -257,5 +257,31 @@
},
"shoutButton": {
"shouted": "empfohlen"
+ },
+
+ "release": {
+ "submit": "freigeben",
+ "cancel": "Abbrechen",
+ "success": "Erfolgreich freigegeben!",
+ "user": {
+ "title": "Nutzer freigeben",
+ "type": "Nutzer",
+ "message": "Bist du sicher, dass du den Nutzer \"{name}\" freigeben möchtest?"
+ },
+ "contribution": {
+ "title": "Beitrag freigeben",
+ "type": "Beitrag",
+ "message": "Bist du sicher, dass du den Beitrag \"{name}\" freigeben möchtest?"
+ },
+ "comment": {
+ "title": "Kommentar freigeben",
+ "type": "Kommentar",
+ "message": "Bist du sicher, dass du den Kommentar \"{name}\" freigeben möchtest?"
+ }
+ },
+ "user": {
+ "avatar": {
+ "submitted": "Upload erfolgreich"
+ }
}
-}
\ No newline at end of file
+}
diff --git a/webapp/locales/en.json b/webapp/locales/en.json
index b4c7d91c2..8330f97b2 100644
--- a/webapp/locales/en.json
+++ b/webapp/locales/en.json
@@ -258,9 +258,29 @@
"shoutButton": {
"shouted": "shouted"
},
+ "release": {
+ "submit": "Release",
+ "cancel": "Cancel",
+ "success": "Released successfully!",
+ "user": {
+ "title": "Release User",
+ "type": "User",
+ "message": "Do you really want to release the user \"{name}\"?"
+ },
+ "contribution": {
+ "title": "Release Contribution",
+ "type": "Contribution",
+ "message": "Do you really want to release the contribution \"{name}\"?"
+ },
+ "comment": {
+ "title": "Release Comment",
+ "type": "Comment",
+ "message": "Do you really want to release the comment from \"{name}\"?"
+ }
+ },
"user": {
"avatar": {
"submitted": "Upload successful"
}
}
-}
\ No newline at end of file
+}