diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js
index 3688aec16..85c584407 100644
--- a/backend/src/middleware/permissionsMiddleware.js
+++ b/backend/src/middleware/permissionsMiddleware.js
@@ -75,6 +75,7 @@ const permissions = shield({
DeleteBadge: isAdmin,
AddUserBadges: isAdmin,
CreateSocialMedia: isAuthenticated,
+ DeleteSocialMedia: isAuthenticated,
// AddBadgeRewarded: isAdmin,
// RemoveBadgeRewarded: isAdmin,
reward: isAdmin,
diff --git a/backend/src/resolvers/socialMedia.js b/backend/src/resolvers/socialMedia.js
index 310375820..ef143a478 100644
--- a/backend/src/resolvers/socialMedia.js
+++ b/backend/src/resolvers/socialMedia.js
@@ -3,6 +3,9 @@ import { neo4jgraphql } from 'neo4j-graphql-js'
export default {
Mutation: {
CreateSocialMedia: async (object, params, context, resolveInfo) => {
+ /**
+ * TODO?: Creates double Nodes!
+ */
const socialMedia = await neo4jgraphql(object, params, context, resolveInfo, false)
const session = context.driver.session()
await session.run(
@@ -15,6 +18,11 @@ export default {
)
session.close()
+ return socialMedia
+ },
+ DeleteSocialMedia: async (object, params, context, resolveInfo) => {
+ const socialMedia = await neo4jgraphql(object, params, context, resolveInfo, false)
+
return socialMedia
}
}
diff --git a/backend/src/resolvers/socialMedia.spec.js b/backend/src/resolvers/socialMedia.spec.js
index b97316543..9d1d76726 100644
--- a/backend/src/resolvers/socialMedia.spec.js
+++ b/backend/src/resolvers/socialMedia.spec.js
@@ -7,9 +7,18 @@ const factory = Factory()
describe('CreateSocialMedia', () => {
let client
let headers
- const mutation = `
+ const mutationC = `
mutation($url: String!) {
CreateSocialMedia(url: $url) {
+ id
+ url
+ }
+ }
+ `
+ const mutationD = `
+ mutation($id: ID!) {
+ DeleteSocialMedia(id: $id) {
+ id
url
}
}
@@ -30,20 +39,63 @@ describe('CreateSocialMedia', () => {
await factory.cleanDatabase()
})
+ describe('unauthenticated', () => {
+ it('throws authorization error', async () => {
+ client = new GraphQLClient(host)
+ const variables = { url: 'http://nsosp.org' }
+ await expect(
+ client.request(mutationC, variables)
+ ).rejects.toThrow('Not Authorised')
+ })
+ })
+
describe('authenticated', () => {
beforeEach(async () => {
headers = await login({ email: 'test@example.org', password: '1234' })
client = new GraphQLClient(host, { headers })
})
+ it('creates social media with correct URL', async () => {
+ const variables = { url: 'http://nsosp.org' }
+ await expect(
+ client.request(mutationC, variables)
+ ).resolves.toEqual(expect.objectContaining({
+ CreateSocialMedia: {
+ id: expect.any(String),
+ url: 'http://nsosp.org'
+ }
+ }))
+ })
+
+ it('deletes social media', async () => {
+ const creationVariables = { url: 'http://nsosp.org' }
+ const { CreateSocialMedia } = await client.request(mutationC, creationVariables)
+ const { id } = CreateSocialMedia
+
+ const deletionVariables = { id }
+ const expected = {
+ DeleteSocialMedia: {
+ id: id,
+ url: 'http://nsosp.org'
+ }
+ }
+ await expect(
+ client.request(mutationD, deletionVariables)
+ ).resolves.toEqual(expected)
+ })
+
it('rejects empty string', async () => {
const variables = { url: '' }
- await expect(client.request(mutation, variables)).rejects.toThrow('Input is not a URL')
+ await expect(
+ client.request(mutationC, variables)
+ ).rejects.toThrow('Input is not a URL')
})
it('validates URLs', async () => {
const variables = { url: 'not-a-url' }
- await expect(client.request(mutation, variables)).rejects.toThrow('Input is not a URL')
+ await expect(
+ client.request(mutationC, variables)
+ ).rejects.toThrow('Input is not a URL')
})
})
})
diff --git a/cypress/integration/common/settings.js b/cypress/integration/common/settings.js
index e1f3cc5a8..b6621ec87 100644
--- a/cypress/integration/common/settings.js
+++ b/cypress/integration/common/settings.js
@@ -77,7 +77,7 @@ Then('I should be on the {string} page', page => {
.should('contain', 'Social media')
})
-Then('I add a social media link', () => {
+When('I add a social media link', () => {
cy.get("input[name='social-media']")
.type('https://freeradical.zone/peter-pan')
.get('button')
@@ -87,7 +87,7 @@ Then('I add a social media link', () => {
Then('it gets saved successfully', () => {
cy.get('.iziToast-message')
- .should('contain', 'Updated user')
+ .should('contain', 'Added social media')
})
Then('the new social media link shows up on the page', () => {
@@ -110,3 +110,13 @@ Then('they should be able to see my social media links', () => {
.get('a[href="https://freeradical.zone/peter-pan"]')
.should('have.length', 1)
})
+
+When('I delete a social media link', () => {
+ cy.get("a[name='delete']")
+ .click()
+})
+
+Then('it gets deleted successfully', () => {
+ cy.get('.iziToast-message')
+ .should('contain', 'Deleted social media')
+})
diff --git a/cypress/integration/user_profile/SocialMedia.feature b/cypress/integration/user_profile/SocialMedia.feature
index 988923c17..d21167c6b 100644
--- a/cypress/integration/user_profile/SocialMedia.feature
+++ b/cypress/integration/user_profile/SocialMedia.feature
@@ -19,3 +19,11 @@ Feature: List Social Media Accounts
Given I have added a social media link
When people visit my profile page
Then they should be able to see my social media links
+
+ Scenario: Deleting Social Media
+ Given I am on the "settings" page
+ And I click on the "Social media" link
+ Then I should be on the "/settings/my-social-media" page
+ Given I have added a social media link
+ When I delete a social media link
+ Then it gets deleted successfully
diff --git a/webapp/locales/de.json b/webapp/locales/de.json
index 14e709866..efaf6f312 100644
--- a/webapp/locales/de.json
+++ b/webapp/locales/de.json
@@ -65,8 +65,10 @@
},
"social-media": {
"name": "Soziale Medien",
+ "placeholder": "Füge eine Social-Media URL hinzu",
"submit": "Link hinzufügen",
- "success": "Profil aktualisiert"
+ "successAdd": "Social-Media hinzugefügt. Profil aktualisiert!",
+ "successDelete": "Social-Media gelöscht. Profil aktualisiert!"
}
},
"admin": {
diff --git a/webapp/locales/en.json b/webapp/locales/en.json
index 2ab796f4a..023f0d362 100644
--- a/webapp/locales/en.json
+++ b/webapp/locales/en.json
@@ -65,8 +65,10 @@
},
"social-media": {
"name": "Social media",
+ "placeholder": "Add social media url",
"submit": "Add link",
- "success": "Updated user profile"
+ "successAdd": "Added social media. Updated user profile!",
+ "successDelete": "Deleted social media. Updated user profile!"
}
},
"admin": {
diff --git a/webapp/pages/settings/my-social-media.spec.js b/webapp/pages/settings/my-social-media.spec.js
index 4f48a2835..559ba87d2 100644
--- a/webapp/pages/settings/my-social-media.spec.js
+++ b/webapp/pages/settings/my-social-media.spec.js
@@ -71,6 +71,40 @@ describe('my-social-media.vue', () => {
const socialMediaLink = wrapper.find('a').attributes().href
expect(socialMediaLink).toBe(socialMediaUrl)
})
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ mutate: jest
+ .fn()
+ .mockRejectedValue({ message: 'Ouch!' })
+ .mockResolvedValueOnce({
+ data: { DeleteSocialMeda: { id: 's1', url: socialMediaUrl } }
+ })
+ },
+ $toast: {
+ error: jest.fn(),
+ success: jest.fn()
+ }
+ }
+ getters = {
+ 'auth/user': () => {
+ return {
+ socialMedia: [{ id: 's1', url: socialMediaUrl }]
+ }
+ }
+ }
+ })
+
+ it('displays a trash sympol after a social media and allows the user to delete it', () => {
+ wrapper = Wrapper()
+ const deleteSelector = wrapper.find({ name: 'delete' })
+ expect(deleteSelector).toEqual({ selector: 'Component' })
+ const icon = wrapper.find({ name: 'trash' })
+ icon.trigger('click')
+ expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
+ })
})
describe('currentUser does not have a social media account linked', () => {
diff --git a/webapp/pages/settings/my-social-media.vue b/webapp/pages/settings/my-social-media.vue
index c031f54a4..462e9af96 100644
--- a/webapp/pages/settings/my-social-media.vue
+++ b/webapp/pages/settings/my-social-media.vue
@@ -8,9 +8,12 @@
{{ link.url }}
+ |
+