diff --git a/CHANGELOG.md b/CHANGELOG.md
index b256df9da..e3183e7a1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,9 +4,29 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
-#### [v0.6.5](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/0.6.4...v0.6.5)
+#### [v0.6.6](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/0.6.5...v0.6.6)
-- updated CHANGELOG.md [`9d9075f`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/9d9075f2117b2eb4b607e7d59ab18c7e655c6ea7)
+- feat: Image Cropping Is Optional [`#4199`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4199)
+- publish workflow [`#4195`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/4195)
+- change user roles is working, test fails [`c528269`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/c528269cb2972e6ea937d31ba22d0e11168141f2)
+- file upload: refactored [`650e83f`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/650e83f4c250389477933a2e7d21d8245b0ce882)
+- change user role: tests are working [`14dfe2a`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/14dfe2ae2cd4a24c06c9229893b33586dfceae4f)
+
+#### [0.6.5](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/v0.6.4...0.6.5)
+
+> 8 February 2021
+
+- - adjusted changelog to ocelot-social repo [`9603882`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/9603882edebf8967e05abfa94e4e1ebf452d4e24)
+- - first steps towards docker image deployment & github autotagging [`5503216`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/5503216ad4a0230ac533042e4a69806590fc2a5a)
+- - deploy structure image [`a60400b`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/a60400b4fe6f59bbb80e1073db4def3ba205e1a7)
+
+#### [v0.6.4](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/0.6.4...v0.6.4)
+
+> 9 February 2021
+
+- chore(release): 0.6.4 [`8b7570d`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/8b7570dc35d0ea431f673a711ac051f1e1320acb)
+- change user roles is working, test fails [`8c3310a`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/8c3310abaf87c0e5597fec4f93fb37d27122c9e7)
+- change user role: tests are working [`f10da4b`](https://github.com/Ocelot-Social-Community/Ocelot-Social/commit/f10da4b09388fe1e2b85abd53f6ffc67c785d4c1)
#### [0.6.4](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/0.6.3...0.6.4)
diff --git a/backend/package.json b/backend/package.json
index 6b9aeb482..0f1ec1f06 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "ocelot-social-backend",
- "version": "0.6.5",
+ "version": "0.6.6",
"description": "GraphQL Backend for ocelot.social",
"repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social",
"author": "ocelot.social Community",
diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js
index dae6f0e48..af70ca2fd 100644
--- a/backend/src/middleware/permissionsMiddleware.js
+++ b/backend/src/middleware/permissionsMiddleware.js
@@ -166,6 +166,7 @@ export default shield(
unpinPost: isAdmin,
UpdateDonations: isAdmin,
GenerateInviteCode: isAuthenticated,
+ switchUserRole: isAdmin,
},
User: {
email: or(isMyOwn, isAdmin),
diff --git a/backend/src/schema/resolvers/users.js b/backend/src/schema/resolvers/users.js
index edc81482f..c6bb64125 100644
--- a/backend/src/schema/resolvers/users.js
+++ b/backend/src/schema/resolvers/users.js
@@ -244,6 +244,31 @@ export default {
session.close()
}
},
+ switchUserRole: async (object, args, context, resolveInfo) => {
+ const { role, id } = args
+
+ if (context.user.id === id) throw new Error('you-cannot-change-your-own-role')
+ const session = context.driver.session()
+ const writeTxResultPromise = session.writeTransaction(async (transaction) => {
+ const switchUserRoleResponse = await transaction.run(
+ `
+ MATCH (user:User {id: $id})
+ SET user.role = $role
+ SET user.updatedAt = toString(datetime())
+ RETURN user {.*}
+ `,
+ { id, role },
+ )
+ const [user] = switchUserRoleResponse.records.map((record) => record.get('user'))
+ return user
+ })
+ try {
+ const user = await writeTxResultPromise
+ return user
+ } finally {
+ session.close()
+ }
+ },
},
User: {
email: async (parent, params, context, resolveInfo) => {
diff --git a/backend/src/schema/resolvers/users.spec.js b/backend/src/schema/resolvers/users.spec.js
index 6509f0e68..e5e818040 100644
--- a/backend/src/schema/resolvers/users.spec.js
+++ b/backend/src/schema/resolvers/users.spec.js
@@ -45,6 +45,18 @@ const deleteUserMutation = gql`
}
`
+const switchUserRoleMutation = gql`
+ mutation($role: UserGroup!, $id: ID!) {
+ switchUserRole(role: $role, id: $id) {
+ name
+ role
+ id
+ updatedAt
+ email
+ }
+ }
+`
+
beforeAll(() => {
const { server } = createServer({
context: () => {
@@ -458,3 +470,71 @@ describe('Delete a User as admin', () => {
})
})
})
+
+describe('switch user role', () => {
+ beforeEach(async () => {
+ user = await Factory.build('user', {
+ id: 'user',
+ role: 'user',
+ })
+ admin = await Factory.build('user', {
+ role: 'admin',
+ id: 'admin',
+ })
+ })
+
+ describe('as simple user', () => {
+ it('cannot change the role', async () => {
+ authenticatedUser = await user.toJson()
+ variables = {
+ id: 'user',
+ role: 'admin',
+ }
+ await expect(mutate({ mutation: switchUserRoleMutation, variables })).resolves.toEqual(
+ expect.objectContaining({
+ errors: [
+ expect.objectContaining({
+ message: 'Not Authorised!',
+ }),
+ ],
+ }),
+ )
+ })
+ })
+
+ describe('as admin', () => {
+ it('changes the role of other user', async () => {
+ authenticatedUser = await admin.toJson()
+ variables = {
+ id: 'user',
+ role: 'moderator',
+ }
+ await expect(mutate({ mutation: switchUserRoleMutation, variables })).resolves.toEqual(
+ expect.objectContaining({
+ data: {
+ switchUserRole: expect.objectContaining({
+ role: 'moderator',
+ }),
+ },
+ }),
+ )
+ })
+
+ it('cannot change own role', async () => {
+ authenticatedUser = await admin.toJson()
+ variables = {
+ id: 'admin',
+ role: 'moderator',
+ }
+ await expect(mutate({ mutation: switchUserRoleMutation, variables })).resolves.toEqual(
+ expect.objectContaining({
+ errors: [
+ expect.objectContaining({
+ message: 'you-cannot-change-your-own-role',
+ }),
+ ],
+ }),
+ )
+ })
+ })
+})
diff --git a/backend/src/schema/types/type/User.gql b/backend/src/schema/types/type/User.gql
index 712eda90c..2290cd4ce 100644
--- a/backend/src/schema/types/type/User.gql
+++ b/backend/src/schema/types/type/User.gql
@@ -215,4 +215,6 @@ type Mutation {
unmuteUser(id: ID!): User
blockUser(id: ID!): User
unblockUser(id: ID!): User
+
+ switchUserRole(role: UserGroup!, id: ID!): User
}
diff --git a/package.json b/package.json
index 462bfc14b..3510526ef 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ocelot-social",
- "version": "0.6.5",
+ "version": "0.6.6",
"description": "Fullstack and API tests with cypress and cucumber for ocelot.social",
"author": "ocelot.social Community",
"license": "MIT",
diff --git a/webapp/graphql/admin/Roles.js b/webapp/graphql/admin/Roles.js
new file mode 100644
index 000000000..531961656
--- /dev/null
+++ b/webapp/graphql/admin/Roles.js
@@ -0,0 +1,28 @@
+import gql from 'graphql-tag'
+
+export const FetchAllRoles = () => {
+ return gql`
+ query {
+ __type(name: "UserGroup") {
+ name
+ enumValues {
+ name
+ }
+ }
+ }
+ `
+}
+
+export const updateUserRole = (role, id) => {
+ return gql`
+ mutation($role: UserGroup!, $id: ID!) {
+ switchUserRole(role: $role, id: $id) {
+ name
+ role
+ id
+ updatedAt
+ email
+ }
+ }
+ `
+}
diff --git a/webapp/locales/de.json b/webapp/locales/de.json
index 4d34757d8..9ef86a7d4 100644
--- a/webapp/locales/de.json
+++ b/webapp/locales/de.json
@@ -63,6 +63,7 @@
"placeholder": "E-Mail, Name oder Beschreibung"
},
"name": "Benutzer",
+ "roleChanged": "Rolle erfolgreich geƤndert!",
"table": {
"columns": {
"createdAt": "Erstellt am",
diff --git a/webapp/locales/en.json b/webapp/locales/en.json
index afb767c14..3c2af7556 100644
--- a/webapp/locales/en.json
+++ b/webapp/locales/en.json
@@ -63,6 +63,7 @@
"placeholder": "e-mail, name or description"
},
"name": "Users",
+ "roleChanged": "Role changed successfully!",
"table": {
"columns": {
"createdAt": "Created at",
diff --git a/webapp/package.json b/webapp/package.json
index 9ad6a157c..65d21d8f2 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -1,6 +1,6 @@
{
"name": "ocelot-social-webapp",
- "version": "0.6.5",
+ "version": "0.6.6",
"description": "ocelot.social Frontend",
"repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social",
"author": "ocelot.social Community",
diff --git a/webapp/pages/admin/users.spec.js b/webapp/pages/admin/users.spec.js
index 37d155b92..e8e624cc1 100644
--- a/webapp/pages/admin/users.spec.js
+++ b/webapp/pages/admin/users.spec.js
@@ -1,27 +1,54 @@
-import { mount } from '@vue/test-utils'
+import { config, mount } from '@vue/test-utils'
+import Vuex from 'vuex'
import Users from './users.vue'
const localVue = global.localVue
+config.stubs['nuxt-link'] = ''
describe('Users', () => {
let wrapper
let Wrapper
- let mocks
+ let getters
- beforeEach(() => {
- mocks = {
- $t: jest.fn(),
- $apollo: {
- loading: false,
- },
- }
- })
+ const mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ loading: false,
+ mutate: jest
+ .fn()
+ .mockRejectedValue({ message: 'Ouch!' })
+ .mockResolvedValue({
+ data: {
+ switchUserRole: {
+ id: 'user',
+ email: 'user@example.org',
+ name: 'User',
+ role: 'moderator',
+ slug: 'user',
+ },
+ },
+ }),
+ },
+ $toast: {
+ error: jest.fn(),
+ success: jest.fn(),
+ },
+ }
describe('mount', () => {
+ getters = {
+ 'auth/isAdmin': () => true,
+ 'auth/user': () => {
+ return { id: 'admin' }
+ },
+ }
+
Wrapper = () => {
+ const store = new Vuex.Store({ getters })
return mount(Users, {
mocks,
localVue,
+ store,
})
}
@@ -69,5 +96,54 @@ describe('Users', () => {
})
})
})
+
+ describe('change roles', () => {
+ beforeAll(() => {
+ wrapper = Wrapper()
+ wrapper.setData({
+ User: [
+ {
+ id: 'admin',
+ email: 'admin@example.org',
+ name: 'Admin',
+ role: 'admin',
+ slug: 'admin',
+ },
+ {
+ id: 'user',
+ email: 'user@example.org',
+ name: 'User',
+ role: 'user',
+ slug: 'user',
+ },
+ ],
+ userRoles: ['user', 'moderator', 'admin'],
+ })
+ })
+
+ it('cannot change own role', () => {
+ const adminRow = wrapper.findAll('tr').at(1)
+ expect(adminRow.find('select').exists()).toBe(false)
+ })
+
+ it('changes the role of another user', () => {
+ const userRow = wrapper.findAll('tr').at(2)
+ userRow.findAll('option').at(1).setSelected()
+ expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
+ expect.objectContaining({
+ variables: {
+ id: 'user',
+ role: 'moderator',
+ },
+ }),
+ )
+ })
+
+ it('toasts a success message after role has changed', () => {
+ const userRow = wrapper.findAll('tr').at(2)
+ userRow.findAll('option').at(1).setSelected()
+ expect(mocks.$toast.success).toHaveBeenCalled()
+ })
+ })
})
})
diff --git a/webapp/pages/admin/users.vue b/webapp/pages/admin/users.vue
index 3d9a4f660..e8b4cfdf5 100644
--- a/webapp/pages/admin/users.vue
+++ b/webapp/pages/admin/users.vue
@@ -48,6 +48,21 @@
{{ scope.row.createdAt | dateTime }}
+
+
+
+
+ {{ scope.row.role }}
+
+
@@ -58,10 +73,12 @@