- If you didn't sign up for If the above button doesn't work, you can also copy the following code into your browser window: {{{ nonce }}}
+ However, this only works if you have registered through our website.
+ If you didn't sign up for Human Connection we recommend you to check it out!
It's a social network from people for people who want to connect and change the world together.
PS: If you ignore this e-mail we will not create an account
diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js
index 8343443c9..df87f743e 100644
--- a/backend/src/middleware/permissionsMiddleware.js
+++ b/backend/src/middleware/permissionsMiddleware.js
@@ -111,6 +111,8 @@ const noEmailFilter = rule({
return !('email' in args)
})
+const publicRegistration = rule()(() => !!CONFIG.PUBLIC_REGISTRATION)
+
// Permissions
const permissions = shield(
{
@@ -137,7 +139,7 @@ const permissions = shield(
'*': deny,
login: allow,
SignupByInvitation: allow,
- Signup: isAdmin,
+ Signup: or(publicRegistration, isAdmin),
SignupVerification: allow,
CreateInvitationCode: and(isAuthenticated, or(not(invitationLimitReached), isAdmin)),
UpdateUser: onlyYourself,
diff --git a/backend/src/models/User.js b/backend/src/models/User.js
index 6448d7450..86900c3ae 100644
--- a/backend/src/models/User.js
+++ b/backend/src/models/User.js
@@ -105,4 +105,8 @@ module.exports = {
target: 'Location',
direction: 'out',
},
+ allowEmbedIframes: {
+ type: 'boolean',
+ default: false,
+ },
}
diff --git a/backend/src/schema/resolvers/embeds/findProvider.js b/backend/src/schema/resolvers/embeds/findProvider.js
index 491cbb9e8..a4240895f 100644
--- a/backend/src/schema/resolvers/embeds/findProvider.js
+++ b/backend/src/schema/resolvers/embeds/findProvider.js
@@ -3,6 +3,7 @@ import path from 'path'
import minimatch from 'minimatch'
let oEmbedProvidersFile = fs.readFileSync(path.join(__dirname, './providers.json'), 'utf8')
+
// some providers allow a format parameter
// we need JSON
oEmbedProvidersFile = oEmbedProvidersFile.replace(/\{format\}/g, 'json')
diff --git a/backend/src/schema/resolvers/users.js b/backend/src/schema/resolvers/users.js
index b5df8111e..06b25b4fa 100644
--- a/backend/src/schema/resolvers/users.js
+++ b/backend/src/schema/resolvers/users.js
@@ -176,6 +176,7 @@ export default {
'about',
'termsAndConditionsAgreedVersion',
'termsAndConditionsAgreedAt',
+ 'allowEmbedIframes',
],
boolean: {
followedByCurrentUser:
diff --git a/backend/src/schema/resolvers/users.spec.js b/backend/src/schema/resolvers/users.spec.js
index 784a48c06..986f4a41f 100644
--- a/backend/src/schema/resolvers/users.spec.js
+++ b/backend/src/schema/resolvers/users.spec.js
@@ -86,6 +86,7 @@ describe('UpdateUser', () => {
name: 'John Doe',
termsAndConditionsAgreedVersion: null,
termsAndConditionsAgreedAt: null,
+ allowEmbedIframes: false,
}
variables = {
diff --git a/backend/src/schema/types/type/User.gql b/backend/src/schema/types/type/User.gql
index f1c38b8d6..d9084dd90 100644
--- a/backend/src/schema/types/type/User.gql
+++ b/backend/src/schema/types/type/User.gql
@@ -27,6 +27,8 @@ type User {
termsAndConditionsAgreedVersion: String
termsAndConditionsAgreedAt: String
+ allowEmbedIframes: Boolean
+
friends: [User]! @relation(name: "FRIENDS", direction: "BOTH")
friendsCount: Int! @cypher(statement: "MATCH (this)<-[: FRIENDS]->(r: User) RETURN COUNT(DISTINCT r)")
@@ -166,6 +168,7 @@ type Mutation {
about: String
termsAndConditionsAgreedVersion: String
termsAndConditionsAgreedAt: String
+ allowEmbedIframes: Boolean
): User
DeleteUser(id: ID!, resource: [Deletable]): User
diff --git a/backend/src/seed/factories/users.js b/backend/src/seed/factories/users.js
index 962f92781..b65be795d 100644
--- a/backend/src/seed/factories/users.js
+++ b/backend/src/seed/factories/users.js
@@ -16,6 +16,7 @@ export default function create() {
about: faker.lorem.paragraph(),
termsAndConditionsAgreedVersion: '0.0.1',
termsAndConditionsAgreedAt: '2019-08-01T10:47:19.212Z',
+ allowEmbedIframes: false,
}
defaults.slug = slugify(defaults.name, { lower: true })
args = {
diff --git a/backend/yarn.lock b/backend/yarn.lock
index ea3a38991..5adc174ce 100644
--- a/backend/yarn.lock
+++ b/backend/yarn.lock
@@ -6182,10 +6182,10 @@ nodemailer-html-to-text@^3.1.0:
dependencies:
html-to-text "^5.1.1"
-nodemailer@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.3.0.tgz#a89b0c62d3937bdcdeecbf55687bd7911b627e12"
- integrity sha512-TEHBNBPHv7Ie/0o3HXnb7xrPSSQmH1dXwQKRaMKDBGt/ZN54lvDVujP6hKkO/vjkIYL9rK8kHSG11+G42Nhxuw==
+nodemailer@^6.3.1:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.3.1.tgz#2784beebac6b9f014c424c54dbdcc5c4d1221346"
+ integrity sha512-j0BsSyaMlyadEDEypK/F+xlne2K5m6wzPYMXS/yxKI0s7jmT1kBx6GEKRVbZmyYfKOsjkeC/TiMVDJBI/w5gMQ==
nodemon@~1.19.3:
version "1.19.3"
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
index ba9b32c18..df7d6ac92 100644
--- a/docker-compose.override.yml
+++ b/docker-compose.override.yml
@@ -15,6 +15,7 @@ services:
- ./webapp:/nitro-web
environment:
- NUXT_BUILD=/tmp/nuxt # avoid file permission issues when `rm -rf .nuxt/`
+ - PUBLIC_REGISTRATION=true
command: yarn run dev
backend:
build:
@@ -28,6 +29,7 @@ services:
- SMTP_PORT=25
- SMTP_IGNORE_TLS=true
- "DEBUG=${DEBUG}"
+ - PUBLIC_REGISTRATION=true
maintenance:
image: humanconnection/maintenance:latest
build:
diff --git a/package.json b/package.json
index 5427090dc..18a46e56d 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
"codecov": "^3.6.1",
"cross-env": "^6.0.3",
"cypress": "^3.4.1",
- "cypress-cucumber-preprocessor": "^1.16.1",
+ "cypress-cucumber-preprocessor": "^1.16.2",
"cypress-file-upload": "^3.3.4",
"cypress-plugin-retries": "^1.3.0",
"dotenv": "^8.1.0",
diff --git a/styleguide b/styleguide
index d46fc1570..808b3c5a9 160000
--- a/styleguide
+++ b/styleguide
@@ -1 +1 @@
-Subproject commit d46fc1570c6bcea328ae4cc3a4892745edea7319
+Subproject commit 808b3c5a9523505cb80b20b50348d29ba9932845
diff --git a/webapp/.env.template b/webapp/.env.template
index bebdeaaaf..fdabcf003 100644
--- a/webapp/.env.template
+++ b/webapp/.env.template
@@ -1,3 +1,4 @@
MAPBOX_TOKEN="pk.eyJ1IjoiaHVtYW4tY29ubmVjdGlvbiIsImEiOiJjajl0cnBubGoweTVlM3VwZ2lzNTNud3ZtIn0.KZ8KK9l70omjXbEkkbHGsQ"
SENTRY_DSN_WEBAPP=
COMMIT=
+PUBLIC_REGISTRATION=false
diff --git a/webapp/components/Editor/Editor.story.js b/webapp/components/Editor/Editor.story.js
index aaaa0eb58..7a69b347f 100644
--- a/webapp/components/Editor/Editor.story.js
+++ b/webapp/components/Editor/Editor.story.js
@@ -5,8 +5,12 @@ import helpers from '~/storybook/helpers'
import Vue from 'vue'
const embed = {
+ image: 'https://i.ytimg.com/vi/ptCcgLM-p8k/maxresdefault_live.jpg',
+ title: 'Video Titel',
+ // html: null,
+ description: 'Video Description',
html:
- 'VIDEO ',
+ 'VIDEO ',
}
const plugins = [
@@ -114,15 +118,12 @@ storiesOf('Editor', module)
}),
template: ` `,
}))
- .add('Embeds', () => ({
+ .add('Embeds with iframe', () => ({
components: { HcEditor },
store: helpers.store,
data: () => ({
users,
content: `
-
- The following link should render a youtube video in addition to the link.
-
https://www.youtube.com/watch?v=qkdXAtO40Fo
@@ -130,3 +131,16 @@ storiesOf('Editor', module)
}),
template: ` `,
}))
+ .add('Embeds with plain link', () => ({
+ components: { HcEditor },
+ store: helpers.store,
+ data: () => ({
+ users,
+ content: `
+
+ https://telegram.org/
+
+ `,
+ }),
+ template: ` `,
+ }))
diff --git a/webapp/components/Editor/Editor.vue b/webapp/components/Editor/Editor.vue
index 8d3ce281b..fa37c64dc 100644
--- a/webapp/components/Editor/Editor.vue
+++ b/webapp/components/Editor/Editor.vue
@@ -342,4 +342,84 @@ li > p {
margin: 0 0 $space-x-small;
}
}
+
+.ProseMirror[contenteditable='false'] {
+ .embed-close-button {
+ display: none;
+ }
+}
+
+.embed-container {
+ position: relative;
+ padding: 0;
+ margin: $space-small auto;
+ overflow: hidden;
+ border-radius: $border-radius-base;
+ border: 1px solid $color-neutral-70;
+ background-color: $color-neutral-90;
+}
+
+.embed-content {
+ width: 100%;
+ height: 100%;
+
+ h4 {
+ margin: $space-small 0 0 $space-small;
+ }
+
+ p,
+ a {
+ display: block;
+ margin: 0 0 0 $space-small;
+ }
+}
+
+.embed-preview-image {
+ width: 100%;
+ height: auto;
+}
+
+.embed-preview-image--clickable {
+ cursor: pointer;
+}
+
+.embed-html {
+ width: 100%;
+
+ iframe {
+ width: 100%;
+ }
+}
+
+.embed-overlay {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+
+ padding: $space-large;
+ background-color: $color-neutral-100;
+}
+
+.embed-buttons {
+ button {
+ margin-right: $space-small;
+ }
+}
+
+.embed-checkbox {
+ display: flex;
+
+ input {
+ margin-right: $space-small;
+ }
+}
+
+.embed-close-button {
+ position: absolute;
+ top: $space-x-small;
+ right: $space-x-small;
+ background-color: rgba(250, 249, 250, 0.6);
+}
diff --git a/webapp/components/Editor/defaultExtensions.spec.js b/webapp/components/Editor/defaultExtensions.spec.js
index 5bf8126b0..78924db55 100644
--- a/webapp/components/Editor/defaultExtensions.spec.js
+++ b/webapp/components/Editor/defaultExtensions.spec.js
@@ -35,7 +35,7 @@ describe('defaultExtensions', () => {
it('renders mentioning as link', () => {
const editor = createEditor()
const expected =
- 'This is a post content mentioning @alicia-luettgen .
'
+ 'This is a post content mentioning @alicia-luettgen .
'
expect(editor.getHTML()).toEqual(expected)
})
})
@@ -49,7 +49,7 @@ describe('defaultExtensions', () => {
it('renders hashtag as link', () => {
const editor = createEditor()
const expected =
- 'This is a post content with a hashtag #metoo .
'
+ 'This is a post content with a hashtag #metoo .
'
expect(editor.getHTML()).toEqual(expected)
})
})
diff --git a/webapp/components/Editor/nodes/Embed.js b/webapp/components/Editor/nodes/Embed.js
index 0a12e06ef..0d7a82a18 100644
--- a/webapp/components/Editor/nodes/Embed.js
+++ b/webapp/components/Editor/nodes/Embed.js
@@ -1,13 +1,12 @@
import { Node } from 'tiptap'
import pasteRule from '../commands/pasteRule'
import { compileToFunctions } from 'vue-template-compiler'
+import Vue from 'vue'
+import EmbedComponent from '~/components/Embed/EmbedComponent'
+
+Vue.component(EmbedComponent)
+const template = ` `
-const template = `
-
-
- {{ dataEmbedUrl }}
-
-`
const compiledTemplate = compileToFunctions(template)
export default class Embed extends Node {
@@ -67,16 +66,13 @@ export default class Embed extends Node {
embedData: {},
}),
async created() {
- if (!this.options) return {}
- this.embedData = await this.options.onEmbed({ url: this.dataEmbedUrl })
+ if (this.options) {
+ this.embedData = await this.options.onEmbed({ url: this.dataEmbedUrl })
+ }
},
computed: {
- embedClass() {
- return this.embedHtml ? 'embed' : ''
- },
- embedHtml() {
- const { html = '' } = this.embedData
- return html
+ componentType() {
+ return EmbedComponent
},
dataEmbedUrl: {
get() {
diff --git a/webapp/components/Editor/nodes/Embed.spec.js b/webapp/components/Editor/nodes/Embed.spec.js
index e38bda061..639f99338 100644
--- a/webapp/components/Editor/nodes/Embed.spec.js
+++ b/webapp/components/Editor/nodes/Embed.spec.js
@@ -1,31 +1,30 @@
-import { shallowMount } from '@vue/test-utils'
+import { shallowMount, createLocalVue } from '@vue/test-utils'
+import Vuex from 'vuex'
+import Styleguide from '@human-connection/styleguide'
import Embed from './Embed'
-let Wrapper
-let propsData
+let Wrapper, propsData, component
const someUrl = 'https://www.youtube.com/watch?v=qkdXAtO40Fo'
+const localVue = createLocalVue()
+
+localVue.use(Vuex)
+localVue.use(Styleguide)
describe('Embed.vue', () => {
beforeEach(() => {
propsData = {}
- const component = new Embed()
- Wrapper = ({ mocks, propsData }) => {
+ component = new Embed()
+ Wrapper = ({ propsData }) => {
return shallowMount(component.view, { propsData })
}
})
- it('renders anchor', () => {
- propsData = {
- node: { attrs: { href: someUrl } },
- }
- expect(Wrapper({ propsData }).is('a')).toBe(true)
- })
-
describe('given a href', () => {
describe('onEmbed returned embed data', () => {
beforeEach(() => {
propsData.options = {
onEmbed: () => ({
+ __typename: 'Embed',
type: 'video',
title: 'Baby Loves Cat',
author: 'Merkley Family',
@@ -49,9 +48,7 @@ describe('Embed.vue', () => {
propsData.node = { attrs: { href: 'https://www.youtube.com/watch?v=qkdXAtO40Fo' } }
const wrapper = Wrapper({ propsData })
await wrapper.html()
- expect(wrapper.find('div iframe').attributes('src')).toEqual(
- 'https://www.youtube.com/embed/qkdXAtO40Fo?feature=oembed',
- )
+ expect(wrapper.contains('embed-component-stub')).toBe(true)
})
})
diff --git a/webapp/components/Editor/nodes/Link.js b/webapp/components/Editor/nodes/Link.js
index 6c015c030..4856566d6 100644
--- a/webapp/components/Editor/nodes/Link.js
+++ b/webapp/components/Editor/nodes/Link.js
@@ -27,6 +27,7 @@ export default class Link extends TipTapLink {
{
...node.attrs,
rel: 'noopener noreferrer nofollow',
+ target: '_blank',
},
0,
],
diff --git a/webapp/components/Editor/plugins/eventHandler.js b/webapp/components/Editor/plugins/eventHandler.js
index c390a066d..807949aa8 100644
--- a/webapp/components/Editor/plugins/eventHandler.js
+++ b/webapp/components/Editor/plugins/eventHandler.js
@@ -10,7 +10,6 @@ export default class EventHandler extends Extension {
new Plugin({
props: {
transformPastedText(text) {
- // console.log('#### transformPastedText', text)
return text.trim()
},
transformPastedHTML(html) {
@@ -33,7 +32,6 @@ export default class EventHandler extends Extension {
.replace(/(\s* \s*)+/gim, '
')
// remove additional linebreaks when last child inside p tags
.replace(/(\s* \s*)+<\/p>/gim, '
')
- // console.log('#### transformPastedHTML', html)
return html
},
// transformPasted(slice) {
diff --git a/webapp/components/Embed/EmbedComponent.spec.js b/webapp/components/Embed/EmbedComponent.spec.js
new file mode 100644
index 000000000..5ad8dd324
--- /dev/null
+++ b/webapp/components/Embed/EmbedComponent.spec.js
@@ -0,0 +1,206 @@
+import { mount, createLocalVue } from '@vue/test-utils'
+import Vuex from 'vuex'
+import Styleguide from '@human-connection/styleguide'
+import EmbedComponent from './EmbedComponent'
+
+let wrapper, propsData, getters, mocks
+const someUrl = 'https://www.youtube.com/watch?v=qkdXAtO40Fo'
+const localVue = createLocalVue()
+
+localVue.use(Vuex)
+localVue.use(Styleguide)
+
+describe('EmbedComponent.vue', () => {
+ const Wrapper = () => {
+ const store = new Vuex.Store({
+ getters,
+ })
+ return mount(EmbedComponent, { propsData, localVue, store, mocks })
+ }
+
+ beforeEach(() => {
+ mocks = {
+ $t: a => a,
+ $apollo: {
+ mutate: jest
+ .fn()
+ .mockResolvedValueOnce({ data: { UpdateUser: { allowEmbedIframes: true } } }),
+ },
+ $toast: {
+ success: jest.fn(),
+ error: jest.fn(),
+ },
+ }
+ propsData = {}
+ getters = {
+ 'auth/user': () => {
+ return { id: 'u5', allowEmbedIframes: false }
+ },
+ }
+ })
+
+ describe('given a href only for a link ', () => {
+ beforeEach(() => {
+ propsData.embedData = {
+ __typename: 'Embed',
+ type: 'link',
+ title: '👻 ✉️ Bruno... le ciel sur répondeur ! 🔮 🧠 - Clément FREZE',
+ author: null,
+ publisher: 'PeerTube.social',
+ date: null,
+ description:
+ 'Salut tout le monde ! Aujourd’hui, une vidéo sur le scepticisme, nous allons parler médiumnité avec le cas de Bruno CHARVET : « Bruno, un nouveau message ». Merci de rester respectueux dans les commentaires : SOURCES : Les sources des vi...',
+ url: 'https://peertube.social/videos/watch/f3cb1945-a8f7-481f-a465-946c6f884e50',
+ image: 'https://peertube.social/static/thumbnails/f3cb1945-a8f7-481f-a465-946c6f884e50.jpg',
+ audio: null,
+ video: null,
+ lang: 'fr',
+ sources: ['resource', 'oembed'],
+ html: null,
+ }
+ wrapper = Wrapper()
+ })
+
+ it('shows the title', () => {
+ expect(wrapper.find('h4').text()).toBe(
+ '👻 ✉️ Bruno... le ciel sur répondeur ! 🔮 🧠 - Clément FREZE',
+ )
+ })
+
+ it('shows the description', () => {
+ expect(wrapper.find('.embed-content p').text()).toBe(
+ 'Salut tout le monde ! Aujourd’hui, une vidéo sur le scepticisme, nous allons parler médiumnité avec le cas de Bruno CHARVET : « Bruno, un nouveau message ». Merci de rester respectueux dans les commentaires : SOURCES : Les sources des vi...',
+ )
+ })
+
+ it('shows preview Images for link', () => {
+ expect(wrapper.find('.embed-preview-image').exists()).toBe(true)
+ })
+ })
+
+ describe('given a href with embed html', () => {
+ describe('onEmbed returned title and description', () => {
+ beforeEach(() => {
+ propsData.embedData = {
+ __typename: 'Embed',
+ title: 'Baby Loves Cat',
+ description:
+ 'She’s incapable of controlling her limbs when her kitty is around. The obsession grows every day. Ps. That’s a sleep sack she’s in. Not a starfish outfit. Al...',
+ }
+ wrapper = Wrapper()
+ })
+
+ it('show the title', () => {
+ expect(wrapper.find('h4').text()).toBe('Baby Loves Cat')
+ })
+
+ it('show the desciption', () => {
+ expect(wrapper.find('.embed-content p').text()).toBe(
+ 'She’s incapable of controlling her limbs when her kitty is around. The obsession grows every day. Ps. That’s a sleep sack she’s in. Not a starfish outfit. Al...',
+ )
+ })
+
+ describe('onEmbed returned embed data with html', () => {
+ beforeEach(() => {
+ propsData.embedData = {
+ __typename: 'Embed',
+ type: 'video',
+ title: 'Baby Loves Cat',
+ author: 'Merkley Family',
+ publisher: 'YouTube',
+ date: '2015-08-16T00:00:00.000Z',
+ description:
+ 'She’s incapable of controlling her limbs when her kitty is around. The obsession grows every day. Ps. That’s a sleep sack she’s in. Not a starfish outfit. Al...',
+ url: someUrl,
+ image: 'https://i.ytimg.com/vi/qkdXAtO40Fo/maxresdefault.jpg',
+ audio: null,
+ video: null,
+ lang: 'de',
+ sources: ['resource', 'oembed'],
+ html:
+ 'VIDEO ',
+ }
+ wrapper = Wrapper()
+ })
+
+ it('shows a simple link when a user closes the embed preview', () => {
+ wrapper.find('.embed-close-button').trigger('click')
+ expect(wrapper.vm.showLinkOnly).toBe(true)
+ })
+
+ it('opens the data privacy overlay when a user clicks on the preview image', () => {
+ wrapper.find('.embed-preview-image--clickable').trigger('click')
+ expect(wrapper.vm.showOverlay).toBe(true)
+ })
+
+ describe('shows iframe', () => {
+ beforeEach(() => {
+ wrapper.setData({ showOverlay: true })
+ })
+
+ it('when user agress', () => {
+ wrapper.find('.ds-button-primary').trigger('click')
+ expect(wrapper.vm.showEmbed).toBe(true)
+ })
+
+ it('does not show iframe when user clicks to cancel', () => {
+ wrapper.find('.ds-button-ghost').trigger('click')
+ expect(wrapper.vm.showEmbed).toBe(false)
+ })
+
+ describe("doesn't set permanently", () => {
+ beforeEach(() => {
+ wrapper.find('.ds-button-primary').trigger('click')
+ })
+
+ it("if user doesn't give consent", () => {
+ expect(wrapper.vm.checkedAlwaysAllowEmbeds).toBe(false)
+ })
+
+ it("doesn't update the user's profile", () => {
+ expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('sets permanently', () => {
+ beforeEach(() => {
+ wrapper.find('input[type=checkbox]').trigger('click')
+ wrapper.find('.ds-button-primary').trigger('click')
+ })
+
+ it('changes setting permanetly when user requests', () => {
+ expect(wrapper.vm.checkedAlwaysAllowEmbeds).toBe(true)
+ })
+
+ it("updates the user's profile", () => {
+ expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
+ })
+ })
+ })
+
+ describe('immediately shows', () => {
+ beforeEach(() => {
+ getters = {
+ 'auth/user': () => {
+ return { id: 'u5', allowEmbedIframes: true }
+ },
+ }
+ wrapper = Wrapper()
+ })
+
+ it('sets showEmbed to true', () => {
+ expect(wrapper.vm.showEmbed).toBe(true)
+ })
+
+ it('the iframe returned from oEmbed', () => {
+ expect(wrapper.find('iframe').html()).toEqual(propsData.embedData.html)
+ })
+
+ it('does not display image to click', () => {
+ expect(wrapper.find('.embed-preview-image--clickable').exists()).toBe(false)
+ })
+ })
+ })
+ })
+ })
+})
diff --git a/webapp/components/Embed/EmbedComponent.vue b/webapp/components/Embed/EmbedComponent.vue
new file mode 100644
index 000000000..5dc8ad00c
--- /dev/null
+++ b/webapp/components/Embed/EmbedComponent.vue
@@ -0,0 +1,153 @@
+
+
+ {{ dataEmbedUrl }}
+
+
+
+
+
+
+
+
+ {{ embedTitle }}
+ {{ embedDescription }}
+
+ {{ dataEmbedUrl }}
+
+
+
+
+
+
+
+
diff --git a/webapp/components/PasswordReset/VerifyNonce.spec.js b/webapp/components/EnterNonce/EnterNonce.spec.js
similarity index 67%
rename from webapp/components/PasswordReset/VerifyNonce.spec.js
rename to webapp/components/EnterNonce/EnterNonce.spec.js
index ebe552f0d..67f1f9073 100644
--- a/webapp/components/PasswordReset/VerifyNonce.spec.js
+++ b/webapp/components/EnterNonce/EnterNonce.spec.js
@@ -1,12 +1,12 @@
import { mount, createLocalVue } from '@vue/test-utils'
-import VerifyNonce from './VerifyNonce.vue'
+import EnterNonce from './EnterNonce.vue'
import Styleguide from '@human-connection/styleguide'
const localVue = createLocalVue()
localVue.use(Styleguide)
-describe('VerifyNonce ', () => {
+describe('EnterNonce ', () => {
let wrapper
let Wrapper
let mocks
@@ -25,28 +25,28 @@ describe('VerifyNonce ', () => {
beforeEach(jest.useFakeTimers)
Wrapper = () => {
- return mount(VerifyNonce, {
+ return mount(EnterNonce, {
mocks,
localVue,
propsData,
})
}
- it('renders a verify nonce form', () => {
+ it('renders an enter nonce form', () => {
wrapper = Wrapper()
- expect(wrapper.find('.verify-nonce').exists()).toBe(true)
+ expect(wrapper.find('form').exists()).toBe(true)
})
- describe('after verification nonce given', () => {
+ describe('after nonce entered', () => {
beforeEach(() => {
wrapper = Wrapper()
wrapper.find('input#nonce').setValue('123456')
wrapper.find('form').trigger('submit')
})
- it('emits `verification`', () => {
+ it('emits `nonceEntered`', () => {
const expected = [[{ nonce: '123456', email: 'mail@example.org' }]]
- expect(wrapper.emitted('verification')).toEqual(expected)
+ expect(wrapper.emitted('nonceEntered')).toEqual(expected)
})
})
})
diff --git a/webapp/components/EnterNonce/EnterNonce.vue b/webapp/components/EnterNonce/EnterNonce.vue
new file mode 100644
index 000000000..d936544ad
--- /dev/null
+++ b/webapp/components/EnterNonce/EnterNonce.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+ {{ $t('components.enter-nonce.form.description') }}
+
+
+
+ {{ $t('components.enter-nonce.form.next') }}
+
+
+
+
+
+
+
diff --git a/webapp/components/PasswordReset/ChangePassword.spec.js b/webapp/components/PasswordReset/ChangePassword.spec.js
index e93d5d00d..b5d85dea7 100644
--- a/webapp/components/PasswordReset/ChangePassword.spec.js
+++ b/webapp/components/PasswordReset/ChangePassword.spec.js
@@ -39,7 +39,7 @@ describe('ChangePassword ', () => {
})
}
- describe('given email and verification nonce', () => {
+ describe('given email and nonce', () => {
beforeEach(() => {
propsData.email = 'mail@example.org'
propsData.nonce = '123456'
@@ -66,7 +66,7 @@ describe('ChangePassword ', () => {
describe('password reset successful', () => {
it('displays success message', () => {
- const expected = 'verify-nonce.form.change-password.success'
+ const expected = 'components.password-reset.change-password.success'
expect(mocks.$t).toHaveBeenCalledWith(expected)
})
diff --git a/webapp/components/PasswordReset/ChangePassword.vue b/webapp/components/PasswordReset/ChangePassword.vue
index 3de4f048a..e45612171 100644
--- a/webapp/components/PasswordReset/ChangePassword.vue
+++ b/webapp/components/PasswordReset/ChangePassword.vue
@@ -1,54 +1,62 @@
-
-
-
-
-
-
-
-
-
- {{ $t('settings.security.change-password.button') }}
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ {{ $t('settings.security.change-password.button') }}
+
+
+
+
+
+
+
-
- {{ $t(`verify-nonce.form.change-password.success`) }}
-
-
-
+
+
+ {{ $t('components.password-reset.change-password.success') }}
+
+
+
+
-
- {{ $t(`verify-nonce.form.change-password.error`) }}
- {{ $t('verify-nonce.form.change-password.help') }}
-
- support@human-connection.org
-
-
+
+
+
+ {{ $t(`components.password-reset.change-password.error`) }}
+
+
+ {{ $t('components.password-reset.change-password.help') }}
+
+ support@human-connection.org
+
+
+
+
-
+
-
diff --git a/webapp/components/PasswordReset/VerifyNonce.vue b/webapp/components/PasswordReset/VerifyNonce.vue
deleted file mode 100644
index 94ae13564..000000000
--- a/webapp/components/PasswordReset/VerifyNonce.vue
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-
-
-
-
-
- {{ $t('verify-nonce.form.description') }}
-
-
-
- {{ $t('verify-nonce.form.next') }}
-
-
-
-
-
-
-
diff --git a/webapp/components/Registration/CreateUserAccount.spec.js b/webapp/components/Registration/CreateUserAccount.spec.js
index 6551211c0..67a14b3c5 100644
--- a/webapp/components/Registration/CreateUserAccount.spec.js
+++ b/webapp/components/Registration/CreateUserAccount.spec.js
@@ -8,6 +8,7 @@ const localVue = createLocalVue()
localVue.use(Styleguide)
config.stubs['sweetalert-icon'] = ' '
config.stubs['client-only'] = ' '
+config.stubs['nuxt-link'] = ' '
describe('CreateUserAccount', () => {
let wrapper, Wrapper, mocks, propsData, stubs
@@ -102,7 +103,9 @@ describe('CreateUserAccount', () => {
it('displays success', async () => {
await action()
- expect(mocks.$t).toHaveBeenCalledWith('registration.create-user-account.success')
+ expect(mocks.$t).toHaveBeenCalledWith(
+ 'components.registration.create-user-account.success',
+ )
})
describe('after timeout', () => {
@@ -130,7 +133,9 @@ describe('CreateUserAccount', () => {
it('displays form errors', async () => {
await action()
- expect(wrapper.find('.backendErrors').text()).toContain('Invalid nonce')
+ expect(mocks.$t).toHaveBeenCalledWith(
+ 'components.registration.create-user-account.error',
+ )
})
})
})
diff --git a/webapp/components/Registration/CreateUserAccount.vue b/webapp/components/Registration/CreateUserAccount.vue
index b5711873c..be01e0bb0 100644
--- a/webapp/components/Registration/CreateUserAccount.vue
+++ b/webapp/components/Registration/CreateUserAccount.vue
@@ -1,117 +1,111 @@
-
-
-
-
-
- {{ $t('registration.create-user-account.success') }}
-
-
-
-
-
-
-
-
-
+
+
+
+
+ {{ $t('components.registration.create-user-account.success') }}
+
+
+
+
+
+
+
+ {{ $t('components.registration.create-user-account.error') }}
+
+
+ {{ $t('components.registration.create-user-account.help') }}
+ {{ supportEmail.label }}
+
+
+ {{ $t('site.back-to-login') }}
+
+
+
+
diff --git a/webapp/pages/password-reset/change-password.vue b/webapp/pages/password-reset/change-password.vue
index 7ab124782..3efdd001b 100644
--- a/webapp/pages/password-reset/change-password.vue
+++ b/webapp/pages/password-reset/change-password.vue
@@ -3,7 +3,11 @@
:email="email"
:nonce="nonce"
@passwordResetResponse="handlePasswordResetResponse"
- />
+ >
+
+ {{ $t('site.back-to-login') }}
+
+
diff --git a/webapp/pages/password-reset/request.vue b/webapp/pages/password-reset/request.vue
index aa1b1ef05..29f8fde9d 100644
--- a/webapp/pages/password-reset/request.vue
+++ b/webapp/pages/password-reset/request.vue
@@ -1,5 +1,9 @@
-
+
+
+ {{ $t('site.back-to-login') }}
+
+
diff --git a/webapp/pages/registration.vue b/webapp/pages/registration.vue
index 7c7f03975..695570d26 100644
--- a/webapp/pages/registration.vue
+++ b/webapp/pages/registration.vue
@@ -1,9 +1,29 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webapp/pages/registration/signup.vue b/webapp/pages/registration/signup.vue
new file mode 100644
index 000000000..721cb6268
--- /dev/null
+++ b/webapp/pages/registration/signup.vue
@@ -0,0 +1,34 @@
+
+
+
+ {{ $t('site.back-to-login') }}
+
+
+
+
+ {{ $t('site.back-to-login') }}
+
+
+
+
diff --git a/webapp/pages/settings.vue b/webapp/pages/settings.vue
index 5795792f9..2d8ba7237 100644
--- a/webapp/pages/settings.vue
+++ b/webapp/pages/settings.vue
@@ -39,6 +39,10 @@ export default {
name: this.$t('settings.blocked-users.name'),
path: `/settings/blocked-users`,
},
+ {
+ name: this.$t('settings.embeds.name'),
+ path: `/settings/embeds`,
+ },
{
name: this.$t('settings.deleteUserAccount.name'),
path: `/settings/delete-account`,
diff --git a/webapp/pages/settings/embeds.vue b/webapp/pages/settings/embeds.vue
new file mode 100644
index 000000000..7b85295c0
--- /dev/null
+++ b/webapp/pages/settings/embeds.vue
@@ -0,0 +1,87 @@
+
+
+
+
+ {{ $t('settings.embeds.status.description') }}
+
+ {{ $t(`settings.embeds.status.disabled.${disabled}`) }}
+
+ .
+
+
+ {{ $t('settings.embeds.status.change.question') }}
+
+
+ {{ $t('settings.embeds.status.change.deny') }}
+
+
+ {{ $t('settings.embeds.status.change.allow') }}
+
+
+ {{ $t('settings.embeds.info-description') }}
+
+
+ {{ provider.provider_name }},
+ {{ provider.provider_url }}
+
+
+
+
+
+
+
diff --git a/webapp/store/auth.js b/webapp/store/auth.js
index 498477660..90c59a8f5 100644
--- a/webapp/store/auth.js
+++ b/webapp/store/auth.js
@@ -86,6 +86,7 @@ export const actions = {
locationName
contributionsCount
commentedCount
+ allowEmbedIframes
termsAndConditionsAgreedVersion
socialMedia {
id
diff --git a/webapp/yarn.lock b/webapp/yarn.lock
index 65bd0b6d5..b6dca2ca6 100644
--- a/webapp/yarn.lock
+++ b/webapp/yarn.lock
@@ -438,10 +438,10 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-block-scoping@^7.6.2":
- version "7.6.2"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.2.tgz#96c33ab97a9ae500cc6f5b19e04a7e6553360a79"
- integrity sha512-zZT8ivau9LOQQaOGC7bQLQOT4XPkPXgN2ERfUgk1X8ql+mVkLc4E8eKk+FO3o0154kxzqenWCorfmEXpEZcrSQ==
+"@babel/plugin-transform-block-scoping@^7.6.3":
+ version "7.6.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.3.tgz#6e854e51fbbaa84351b15d4ddafe342f3a5d542a"
+ integrity sha512-7hvrg75dubcO3ZI2rjYTzUrEuh1E9IyDEhhB6qfcooxhDA33xx2MasuLVgdxzcP6R/lipAC6n9ub9maNW6RKdw==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
lodash "^4.17.13"
@@ -563,10 +563,10 @@
"@babel/helper-module-transforms" "^7.1.0"
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-named-capturing-groups-regex@^7.6.2":
- version "7.6.2"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.2.tgz#c1ca0bb84b94f385ca302c3932e870b0fb0e522b"
- integrity sha512-xBdB+XOs+lgbZc2/4F5BVDVcDNS4tcSKQc96KmlqLEAwz6tpYPEvPdmDfvVG0Ssn8lAhronaRs6Z6KSexIpK5g==
+"@babel/plugin-transform-named-capturing-groups-regex@^7.6.3":
+ version "7.6.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.3.tgz#aaa6e409dd4fb2e50b6e2a91f7e3a3149dbce0cf"
+ integrity sha512-jTkk7/uE6H2s5w6VlMHeWuH+Pcy2lmdwFoeWCVnvIrDUnB5gQqTVI8WfmEAhF2CDEarGrknZcmSFg1+bkfCoSw==
dependencies:
regexpu-core "^4.6.0"
@@ -679,10 +679,10 @@
"@babel/helper-regex" "^7.4.4"
regexpu-core "^4.6.0"
-"@babel/preset-env@^7.4.5", "@babel/preset-env@^7.6.2", "@babel/preset-env@~7.6.2":
- version "7.6.2"
- resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.6.2.tgz#abbb3ed785c7fe4220d4c82a53621d71fc0c75d3"
- integrity sha512-Ru7+mfzy9M1/YTEtlDS8CD45jd22ngb9tXnn64DvQK3ooyqSw9K4K9DUWmYknTTVk4TqygL9dqCrZgm1HMea/Q==
+"@babel/preset-env@^7.4.5", "@babel/preset-env@^7.6.2", "@babel/preset-env@~7.6.3":
+ version "7.6.3"
+ resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.6.3.tgz#9e1bf05a2e2d687036d24c40e4639dc46cef2271"
+ integrity sha512-CWQkn7EVnwzlOdR5NOm2+pfgSNEZmvGjOhlCHBDq0J8/EStr+G+FvPEiz9B56dR6MoiUFjXhfE4hjLoAKKJtIQ==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
@@ -700,7 +700,7 @@
"@babel/plugin-transform-arrow-functions" "^7.2.0"
"@babel/plugin-transform-async-to-generator" "^7.5.0"
"@babel/plugin-transform-block-scoped-functions" "^7.2.0"
- "@babel/plugin-transform-block-scoping" "^7.6.2"
+ "@babel/plugin-transform-block-scoping" "^7.6.3"
"@babel/plugin-transform-classes" "^7.5.5"
"@babel/plugin-transform-computed-properties" "^7.2.0"
"@babel/plugin-transform-destructuring" "^7.6.0"
@@ -715,7 +715,7 @@
"@babel/plugin-transform-modules-commonjs" "^7.6.0"
"@babel/plugin-transform-modules-systemjs" "^7.5.0"
"@babel/plugin-transform-modules-umd" "^7.2.0"
- "@babel/plugin-transform-named-capturing-groups-regex" "^7.6.2"
+ "@babel/plugin-transform-named-capturing-groups-regex" "^7.6.3"
"@babel/plugin-transform-new-target" "^7.4.4"
"@babel/plugin-transform-object-super" "^7.5.5"
"@babel/plugin-transform-parameters" "^7.4.4"
@@ -728,7 +728,7 @@
"@babel/plugin-transform-template-literals" "^7.4.4"
"@babel/plugin-transform-typeof-symbol" "^7.2.0"
"@babel/plugin-transform-unicode-regex" "^7.6.2"
- "@babel/types" "^7.6.0"
+ "@babel/types" "^7.6.3"
browserslist "^4.6.0"
core-js-compat "^3.1.1"
invariant "^2.2.2"
diff --git a/yarn.lock b/yarn.lock
index 8d561ef5e..231e6100e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1877,10 +1877,10 @@ cucumber@^4.2.1:
util-arity "^1.0.2"
verror "^1.9.0"
-cypress-cucumber-preprocessor@^1.16.1:
- version "1.16.1"
- resolved "https://registry.yarnpkg.com/cypress-cucumber-preprocessor/-/cypress-cucumber-preprocessor-1.16.1.tgz#2ac7e0e53396334c052aeed8b5e61e08616f73a2"
- integrity sha512-m8Z5t9hSc10kv47qK0fV/JlCboCwQVxgTa+WhnCjOPB7YBnX/en4f0O8l27yaZbZyHan7JBoJvpfzINlaOKafg==
+cypress-cucumber-preprocessor@^1.16.2:
+ version "1.16.2"
+ resolved "https://registry.yarnpkg.com/cypress-cucumber-preprocessor/-/cypress-cucumber-preprocessor-1.16.2.tgz#79e0ce7e7afa781f752711f7284a3bf48aa99ab8"
+ integrity sha512-jDJuQnnzrOrO+4PRt+VKFkHxHO7DplJACXOMUHLLWcL7vjlRUkIG4+QWnOkn/Py3yOhv9Rmuug8Iil5+FV8wEw==
dependencies:
"@cypress/browserify-preprocessor" "^2.1.1"
chai "^4.1.2"