diff --git a/cypress/fixtures/onourjourney.png b/cypress/fixtures/onourjourney.png
new file mode 100644
index 000000000..8e606fabd
Binary files /dev/null and b/cypress/fixtures/onourjourney.png differ
diff --git a/cypress/integration/common/profile.js b/cypress/integration/common/profile.js
new file mode 100644
index 000000000..cb5689f63
--- /dev/null
+++ b/cypress/integration/common/profile.js
@@ -0,0 +1,34 @@
+import { When, Then } from 'cypress-cucumber-preprocessor/steps'
+
+/* global cy */
+
+When('I visit my profile page', () => {
+ cy.openPage('profile/peter-pan')
+})
+
+Then('I should be able to change my profile picture', () => {
+ const avatarUpload = 'onourjourney.png'
+
+ cy.fixture(avatarUpload, 'base64').then(fileContent => {
+ cy.get('#customdropzone').upload(
+ { fileContent, fileName: avatarUpload, mimeType: 'image/png' },
+ { subjectType: 'drag-n-drop' },
+ )
+ })
+ cy.get('#customdropzone')
+ .should('have.attr', 'style')
+ .and('contains', 'onourjourney')
+ cy.contains('.iziToast-message', 'Upload successful')
+ .should('have.length', 1)
+})
+
+When("I visit another user's profile page", () => {
+ cy.openPage('profile/peter-pan')
+})
+
+Then('I cannot upload a picture', () => {
+ cy.get('.ds-card-content')
+ .children()
+ .should('not.have.id', 'customdropzone')
+ .should('have.class', 'ds-avatar')
+})
\ No newline at end of file
diff --git a/cypress/integration/common/settings.js b/cypress/integration/common/settings.js
index b6621ec87..664ffcff8 100644
--- a/cypress/integration/common/settings.js
+++ b/cypress/integration/common/settings.js
@@ -45,6 +45,7 @@ When('people visit my profile page', url => {
cy.openPage('/profile/peter-pan')
})
+
When('they can see the text in the info box below my avatar', () => {
cy.contains(aboutMeText)
})
diff --git a/cypress/integration/user_profile/UploadUserProfileImage.feature b/cypress/integration/user_profile/UploadUserProfileImage.feature
new file mode 100644
index 000000000..b46a31de8
--- /dev/null
+++ b/cypress/integration/user_profile/UploadUserProfileImage.feature
@@ -0,0 +1,18 @@
+Feature: Upload UserProfile Image
+ As a user
+ I would like to be able to add an avatar/profile pic to my profile
+ So that I can personalize my profile
+
+
+ Background:
+ Given I have a user account
+
+ Scenario: Change my UserProfile Image
+ Given I am logged in
+ And I visit my profile page
+ Then I should be able to change my profile picture
+
+ Scenario: Unable to change another user's avatar
+ Given I am logged in with a "user" role
+ And I visit another user's profile page
+ Then I cannot upload a picture
\ No newline at end of file
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index a7cb76a27..f6253af20 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -13,7 +13,7 @@
// Cypress.Commands.add('login', (email, password) => { ... })
/* globals Cypress cy */
-
+import 'cypress-file-upload'
import { getLangByName } from './helpers'
import users from '../fixtures/users.json'
diff --git a/package.json b/package.json
index 0c2e47271..a37c40327 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"cross-env": "^5.2.0",
"cypress": "^3.3.1",
"cypress-cucumber-preprocessor": "^1.11.2",
+ "cypress-file-upload": "^3.1.2",
"cypress-plugin-retries": "^1.2.2",
"dotenv": "^8.0.0",
"faker": "^4.1.0",
@@ -30,4 +31,4 @@
"neo4j-driver": "^1.7.4",
"npm-run-all": "^4.1.5"
}
-}
+}
\ No newline at end of file
diff --git a/webapp/components/Upload/index.vue b/webapp/components/Upload/index.vue
new file mode 100644
index 000000000..831edd2f8
--- /dev/null
+++ b/webapp/components/Upload/index.vue
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
diff --git a/webapp/components/Upload/spec.js b/webapp/components/Upload/spec.js
new file mode 100644
index 000000000..85215ea59
--- /dev/null
+++ b/webapp/components/Upload/spec.js
@@ -0,0 +1,71 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils'
+import Upload from '.'
+import Vuex from 'vuex'
+import Styleguide from '@human-connection/styleguide'
+
+const localVue = createLocalVue()
+
+localVue.use(Vuex)
+localVue.use(Styleguide)
+
+describe('Upload', () => {
+ let wrapper
+
+ const mocks = {
+ $apollo: {
+ mutate: jest
+ .fn()
+ .mockResolvedValueOnce({
+ data: { UpdateUser: { id: 'upload1', avatar: '/upload/avatar.jpg' } },
+ })
+ .mockRejectedValue({
+ message: 'File upload unsuccessful! Whatcha gonna do?',
+ }),
+ },
+ $toast: {
+ success: jest.fn(),
+ error: jest.fn(),
+ },
+ }
+
+ const propsData = {
+ user: {
+ avatar: '/api/generic.jpg',
+ },
+ }
+
+ const file = {
+ filename: 'avatar.jpg',
+ previewElement: {
+ classList: {
+ remove: jest.fn(),
+ add: jest.fn(),
+ },
+ querySelectorAll: jest.fn().mockReturnValue([
+ {
+ alt: '',
+ style: {
+ 'background-image': '/api/generic.jpg',
+ },
+ },
+ ]),
+ },
+ }
+
+ const dataUrl = 'avatar.jpg'
+
+ beforeEach(() => {
+ jest.useFakeTimers()
+ wrapper = shallowMount(Upload, { localVue, propsData, mocks })
+ })
+
+ it('sends a the UpdateUser mutation when vddrop is called', () => {
+ wrapper.vm.vddrop([{ filename: 'avatar.jpg' }])
+ expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
+ })
+
+ it('thumbnail', () => {
+ wrapper.vm.thumbnail(file, dataUrl)
+ expect(file.previewElement.classList.add).toHaveBeenCalledTimes(1)
+ })
+})
diff --git a/webapp/locales/en.json b/webapp/locales/en.json
index 186b31d41..c4d21b6e4 100644
--- a/webapp/locales/en.json
+++ b/webapp/locales/en.json
@@ -247,5 +247,10 @@
},
"shoutButton": {
"shouted": "shouted"
+ },
+ "user": {
+ "avatar": {
+ "submitted": "Upload successful"
+ }
}
}
\ No newline at end of file
diff --git a/webapp/package.json b/webapp/package.json
index 8018ea667..e6f73f880 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -67,6 +67,7 @@
"jsonwebtoken": "~8.5.1",
"linkify-it": "~2.1.0",
"nuxt": "~2.7.1",
+ "nuxt-dropzone": "^1.0.2",
"nuxt-env": "~0.1.0",
"stack-utils": "^1.0.2",
"string-hash": "^1.1.3",
@@ -76,6 +77,7 @@
"vue-count-to": "~1.0.13",
"vue-izitoast": "1.1.2",
"vue-sweetalert-icons": "~3.2.0",
+ "vue2-dropzone": "^3.5.9",
"vuex-i18n": "~1.11.0",
"zxcvbn": "^4.4.2"
},
@@ -111,4 +113,4 @@
"vue-jest": "~3.0.4",
"vue-svg-loader": "~0.12.0"
}
-}
\ No newline at end of file
+}
diff --git a/webapp/pages/profile/_id/_slug.vue b/webapp/pages/profile/_id/_slug.vue
index 3dfb2c751..b38458a16 100644
--- a/webapp/pages/profile/_id/_slug.vue
+++ b/webapp/pages/profile/_id/_slug.vue
@@ -14,7 +14,12 @@
:class="{'disabled-content': user.disabled}"
style="position: relative; height: auto;"
>
+
- {{ link.username }}
+ {{ 'link.username' }}
@@ -327,6 +332,7 @@ import HcBadges from '~/components/Badges.vue'
import HcLoadMore from '~/components/LoadMore.vue'
import HcEmpty from '~/components/Empty.vue'
import ContentMenu from '~/components/ContentMenu'
+import HcUpload from '~/components/Upload'
export default {
components: {
@@ -338,6 +344,7 @@ export default {
HcLoadMore,
HcEmpty,
ContentMenu,
+ HcUpload,
},
transition: {
name: 'slide-up',
diff --git a/webapp/plugins/apollo-config.js b/webapp/plugins/apollo-config.js
index 83ec452e3..e095aaba2 100644
--- a/webapp/plugins/apollo-config.js
+++ b/webapp/plugins/apollo-config.js
@@ -1,5 +1,6 @@
export default ({ app }) => {
const backendUrl = process.env.GRAPHQL_URI || 'http://localhost:4000'
+
return {
httpEndpoint: process.server ? backendUrl : '/api',
httpLinkOptions: {
diff --git a/webapp/yarn.lock b/webapp/yarn.lock
index e244c215e..819186689 100644
--- a/webapp/yarn.lock
+++ b/webapp/yarn.lock
@@ -3968,6 +3968,11 @@ dotenv@^6.0.0:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064"
integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==
+dropzone@^5.5.1:
+ version "5.5.1"
+ resolved "https://registry.yarnpkg.com/dropzone/-/dropzone-5.5.1.tgz#06e2f513e61d6aa363d4b556f18574f47cf7ba26"
+ integrity sha512-3VduRWLxx9hbVr42QieQN25mx/I61/mRdUSuxAmDGdDqZIN8qtP7tcKMa3KfpJjuGjOJGYYUzzeq6eGDnkzesA==
+
duplexer3@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
@@ -7579,6 +7584,13 @@ number-is-nan@^1.0.0:
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
+nuxt-dropzone@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/nuxt-dropzone/-/nuxt-dropzone-1.0.2.tgz#7b39014ebf4c2084ea5c976f8d9f7b3cead2c7af"
+ integrity sha512-Oj6YrQxNH5KhCyFSFz2O809u23+cFAevBTdcld88qakbR2l5stTQjrv8VJ9beaqfenT9kKEkhYQT0mXc3nUdKw==
+ dependencies:
+ vue2-dropzone "3.5.8"
+
nuxt-env@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/nuxt-env/-/nuxt-env-0.1.0.tgz#8ac50b9ff45391ad3044ea932cbd05f06a585f87"
@@ -11155,6 +11167,20 @@ vue-template-es2015-compiler@^1.6.0, vue-template-es2015-compiler@^1.9.0:
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
+vue2-dropzone@3.5.8:
+ version "3.5.8"
+ resolved "https://registry.yarnpkg.com/vue2-dropzone/-/vue2-dropzone-3.5.8.tgz#cbe92d5424b5cc62c4d4ad62814d0cf6f3bb6cda"
+ integrity sha512-32rLGSx+mLKhyzxRz4CdeNT9JmbO6NsYX8m83WYqrf2ilRbm6KSZmUqZ8EIT+2dwq8EzY9jdrWlWuZJRBFPUGw==
+ dependencies:
+ dropzone "^5.5.1"
+
+vue2-dropzone@^3.5.9:
+ version "3.5.9"
+ resolved "https://registry.yarnpkg.com/vue2-dropzone/-/vue2-dropzone-3.5.9.tgz#a63999a45a7aad24d4c21e3d35be409b4e6bdce8"
+ integrity sha512-nJz6teulVKlZIAeKgvPU7wBI/gzfIgqDOrEp1okSkQIkdprDVCoM0U7XWM0NOM4AAVX+4XGRtMoocYWdTYb3bQ==
+ dependencies:
+ dropzone "^5.5.1"
+
vue@^2.6.10, vue@^2.6.6:
version "2.6.10"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
diff --git a/yarn.lock b/yarn.lock
index 16acc6407..1ed66cb51 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1815,6 +1815,11 @@ cypress-cucumber-preprocessor@^1.11.2:
glob "^7.1.2"
through "^2.3.8"
+cypress-file-upload@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-3.1.2.tgz#4a0024f99ca157565bf2b20c110e6e6874da28cb"
+ integrity sha512-gZE2G7ZTD2Y8APrcgs+ATRMKs/IgH2rafCmi+8o99q5sDoNRLR+XKxOcoyWLehj9raGnO98YDYO8DY7k1VMGBw==
+
cypress-plugin-retries@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/cypress-plugin-retries/-/cypress-plugin-retries-1.2.2.tgz#7235371ca575ad9e16f883169e7f1588379f80f2"