mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 01:46:07 +00:00
Merge remote-tracking branch 'origin/master' into 3110-featuredlt-connector-gradido-transaktionen-auf-tangle-senden-und-empfangen
This commit is contained in:
commit
ba026ae335
37
.github/dependabot_backend.yml
vendored
Normal file
37
.github/dependabot_backend.yml
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
directory: "/backend"
|
||||
rebase-strategy: "disabled"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: "saturday"
|
||||
timezone: "Europe/Berlin"
|
||||
time: "03:00"
|
||||
labels:
|
||||
- "devops"
|
||||
- "service:backend"
|
||||
|
||||
- package-ecosystem: docker
|
||||
directory: "/backend"
|
||||
rebase-strategy: "disabled"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: "saturday"
|
||||
timezone: "Europe/Berlin"
|
||||
time: "03:00"
|
||||
labels:
|
||||
- "devops"
|
||||
- "service:docker"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
rebase-strategy: "disabled"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: "saturday"
|
||||
timezone: "Europe/Berlin"
|
||||
time: "03:00"
|
||||
labels:
|
||||
- "devops"
|
||||
16
CHANGELOG.md
16
CHANGELOG.md
@ -4,8 +4,24 @@ 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).
|
||||
|
||||
#### [1.23.0](https://github.com/gradido/gradido/compare/1.22.3...1.23.0)
|
||||
|
||||
- refactor(frontend): add contribution by link information to locales [`#3144`](https://github.com/gradido/gradido/pull/3144)
|
||||
- fix(admin): user role in admin interface [`#3153`](https://github.com/gradido/gradido/pull/3153)
|
||||
- feat(backend): 3030 feature role administration backend [`#3074`](https://github.com/gradido/gradido/pull/3074)
|
||||
- feat(other): iota-tangle-connector sending transaction [`#3132`](https://github.com/gradido/gradido/pull/3132)
|
||||
- feat(other): proper reporting for failing end-to-end tests [`#3096`](https://github.com/gradido/gradido/pull/3096)
|
||||
- fix(other): add missing volume for dlt-connector dev docker [`#3134`](https://github.com/gradido/gradido/pull/3134)
|
||||
- fix(backend): semaphore parallel redeemTransactionLink test [`#3133`](https://github.com/gradido/gradido/pull/3133)
|
||||
- feat(other): iota-tangle-connector mit Hello World Message als separates Modul [`#3118`](https://github.com/gradido/gradido/pull/3118)
|
||||
- refactor(database): fix database public key lengths [`#3026`](https://github.com/gradido/gradido/pull/3026)
|
||||
- refactor(dht): eslint dht import [`#3044`](https://github.com/gradido/gradido/pull/3044)
|
||||
|
||||
#### [1.22.3](https://github.com/gradido/gradido/compare/1.22.2...1.22.3)
|
||||
|
||||
> 6 July 2023
|
||||
|
||||
- chore(release): v1.22.3 [`#3131`](https://github.com/gradido/gradido/pull/3131)
|
||||
- fix(backend): corrected email-link [`#3129`](https://github.com/gradido/gradido/pull/3129)
|
||||
|
||||
#### [1.22.2](https://github.com/gradido/gradido/compare/1.22.1...1.22.2)
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"description": "Administraion Interface for Gradido",
|
||||
"main": "index.js",
|
||||
"author": "Moriz Wahl",
|
||||
"version": "1.22.3",
|
||||
"version": "1.23.0",
|
||||
"license": "Apache-2.0",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
|
||||
@ -21,6 +21,7 @@ const mocks = {
|
||||
moderator: {
|
||||
id: 0,
|
||||
name: 'test moderator',
|
||||
roles: ['ADMIN'],
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -45,7 +46,7 @@ describe('ChangeUserRoleFormular', () => {
|
||||
propsData = {
|
||||
item: {
|
||||
userId: 1,
|
||||
isAdmin: null,
|
||||
roles: [],
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
@ -61,7 +62,7 @@ describe('ChangeUserRoleFormular', () => {
|
||||
propsData = {
|
||||
item: {
|
||||
userId: 0,
|
||||
isAdmin: null,
|
||||
roles: ['ADMIN'],
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
@ -88,7 +89,7 @@ describe('ChangeUserRoleFormular', () => {
|
||||
propsData = {
|
||||
item: {
|
||||
userId: 1,
|
||||
isAdmin: null,
|
||||
roles: [],
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
@ -120,13 +121,13 @@ describe('ChangeUserRoleFormular', () => {
|
||||
beforeEach(() => {
|
||||
apolloMutateMock.mockResolvedValue({
|
||||
data: {
|
||||
setUserRole: new Date(),
|
||||
setUserRole: 'ADMIN',
|
||||
},
|
||||
})
|
||||
propsData = {
|
||||
item: {
|
||||
userId: 1,
|
||||
isAdmin: null,
|
||||
roles: ['USER'],
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
@ -134,7 +135,7 @@ describe('ChangeUserRoleFormular', () => {
|
||||
})
|
||||
|
||||
it('has selected option set to "usual user"', () => {
|
||||
expect(wrapper.find('select.role-select').element.value).toBe('user')
|
||||
expect(wrapper.find('select.role-select').element.value).toBe('USER')
|
||||
})
|
||||
|
||||
describe('change select to', () => {
|
||||
@ -149,7 +150,7 @@ describe('ChangeUserRoleFormular', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('new role', () => {
|
||||
describe('new role "MODERATOR"', () => {
|
||||
beforeEach(() => {
|
||||
rolesToSelect.at(1).setSelected()
|
||||
})
|
||||
@ -181,19 +182,267 @@ describe('ChangeUserRoleFormular', () => {
|
||||
mutation: setUserRole,
|
||||
variables: {
|
||||
userId: 1,
|
||||
isAdmin: true,
|
||||
role: 'MODERATOR',
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('emits "updateIsAdmin"', () => {
|
||||
expect(wrapper.emitted('updateIsAdmin')).toEqual(
|
||||
it('emits "updateRoles" with role moderator', () => {
|
||||
expect(wrapper.emitted('updateRoles')).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.arrayContaining([
|
||||
{
|
||||
userId: 1,
|
||||
isAdmin: expect.any(Date),
|
||||
roles: ['MODERATOR'],
|
||||
},
|
||||
]),
|
||||
]),
|
||||
)
|
||||
})
|
||||
|
||||
it('toasts success message', () => {
|
||||
expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo')
|
||||
})
|
||||
})
|
||||
|
||||
describe('confirm role change with error', () => {
|
||||
beforeEach(async () => {
|
||||
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
|
||||
apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
|
||||
await wrapper.find('button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
})
|
||||
|
||||
it('toasts an error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('new role "ADMIN"', () => {
|
||||
beforeEach(() => {
|
||||
rolesToSelect.at(2).setSelected()
|
||||
})
|
||||
|
||||
it('has "change_user_role" button enabled', () => {
|
||||
expect(wrapper.find('button.btn.btn-danger').exists()).toBe(true)
|
||||
expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
describe('clicking the "change_user_role" button', () => {
|
||||
beforeEach(async () => {
|
||||
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
|
||||
spy.mockImplementation(() => Promise.resolve(true))
|
||||
await wrapper.find('button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
})
|
||||
|
||||
it('calls the modal', () => {
|
||||
expect(wrapper.emitted('showModal'))
|
||||
expect(spy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
describe('confirm role change with success', () => {
|
||||
it('calls the API', () => {
|
||||
expect(apolloMutateMock).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
mutation: setUserRole,
|
||||
variables: {
|
||||
userId: 1,
|
||||
role: 'ADMIN',
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('emits "updateRoles" with role moderator', () => {
|
||||
expect(wrapper.emitted('updateRoles')).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.arrayContaining([
|
||||
{
|
||||
userId: 1,
|
||||
roles: ['ADMIN'],
|
||||
},
|
||||
]),
|
||||
]),
|
||||
)
|
||||
})
|
||||
|
||||
it('toasts success message', () => {
|
||||
expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo')
|
||||
})
|
||||
})
|
||||
|
||||
describe('confirm role change with error', () => {
|
||||
beforeEach(async () => {
|
||||
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
|
||||
apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
|
||||
await wrapper.find('button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
})
|
||||
|
||||
it('toasts an error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('user has role "moderator"', () => {
|
||||
beforeEach(() => {
|
||||
apolloMutateMock.mockResolvedValue({
|
||||
data: {
|
||||
setUserRole: null,
|
||||
},
|
||||
})
|
||||
propsData = {
|
||||
item: {
|
||||
userId: 1,
|
||||
roles: ['MODERATOR'],
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
rolesToSelect = wrapper.find('select.role-select').findAll('option')
|
||||
})
|
||||
|
||||
it('has selected option set to "MODERATOR"', () => {
|
||||
expect(wrapper.find('select.role-select').element.value).toBe('MODERATOR')
|
||||
})
|
||||
|
||||
describe('change select to', () => {
|
||||
describe('same role', () => {
|
||||
it('has "change_user_role" button disabled', () => {
|
||||
expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('does not call the API', () => {
|
||||
rolesToSelect.at(1).setSelected()
|
||||
expect(apolloMutateMock).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('new role "USER"', () => {
|
||||
beforeEach(() => {
|
||||
rolesToSelect.at(0).setSelected()
|
||||
})
|
||||
|
||||
it('has "change_user_role" button enabled', () => {
|
||||
expect(wrapper.find('button.btn.btn-danger').exists()).toBe(true)
|
||||
expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
describe('clicking the "change_user_role" button', () => {
|
||||
beforeEach(async () => {
|
||||
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
|
||||
spy.mockImplementation(() => Promise.resolve(true))
|
||||
await wrapper.find('button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
})
|
||||
|
||||
it('calls the modal', () => {
|
||||
expect(wrapper.emitted('showModal'))
|
||||
expect(spy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
describe('confirm role change with success', () => {
|
||||
it('calls the API', () => {
|
||||
expect(apolloMutateMock).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
mutation: setUserRole,
|
||||
variables: {
|
||||
userId: 1,
|
||||
role: 'USER',
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('emits "updateRoles"', () => {
|
||||
expect(wrapper.emitted('updateRoles')).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.arrayContaining([
|
||||
{
|
||||
userId: 1,
|
||||
roles: [],
|
||||
},
|
||||
]),
|
||||
]),
|
||||
)
|
||||
})
|
||||
|
||||
it('toasts success message', () => {
|
||||
expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo')
|
||||
})
|
||||
})
|
||||
|
||||
describe('confirm role change with error', () => {
|
||||
beforeEach(async () => {
|
||||
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
|
||||
apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
|
||||
await wrapper.find('button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
})
|
||||
|
||||
it('toasts an error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('new role "ADMIN"', () => {
|
||||
beforeEach(() => {
|
||||
rolesToSelect.at(2).setSelected()
|
||||
})
|
||||
|
||||
it('has "change_user_role" button enabled', () => {
|
||||
expect(wrapper.find('button.btn.btn-danger').exists()).toBe(true)
|
||||
expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
describe('clicking the "change_user_role" button', () => {
|
||||
beforeEach(async () => {
|
||||
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
|
||||
spy.mockImplementation(() => Promise.resolve(true))
|
||||
await wrapper.find('button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
})
|
||||
|
||||
it('calls the modal', () => {
|
||||
expect(wrapper.emitted('showModal'))
|
||||
expect(spy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
describe('confirm role change with success', () => {
|
||||
it('calls the API', () => {
|
||||
expect(apolloMutateMock).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
mutation: setUserRole,
|
||||
variables: {
|
||||
userId: 1,
|
||||
role: 'ADMIN',
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('emits "updateRoles"', () => {
|
||||
expect(wrapper.emitted('updateRoles')).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.arrayContaining([
|
||||
{
|
||||
userId: 1,
|
||||
roles: ['ADMIN'],
|
||||
},
|
||||
]),
|
||||
]),
|
||||
@ -232,7 +481,7 @@ describe('ChangeUserRoleFormular', () => {
|
||||
propsData = {
|
||||
item: {
|
||||
userId: 1,
|
||||
isAdmin: new Date(),
|
||||
roles: ['ADMIN'],
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
@ -240,7 +489,7 @@ describe('ChangeUserRoleFormular', () => {
|
||||
})
|
||||
|
||||
it('has selected option set to "admin"', () => {
|
||||
expect(wrapper.find('select.role-select').element.value).toBe('admin')
|
||||
expect(wrapper.find('select.role-select').element.value).toBe('ADMIN')
|
||||
})
|
||||
|
||||
describe('change select to', () => {
|
||||
@ -251,11 +500,12 @@ describe('ChangeUserRoleFormular', () => {
|
||||
|
||||
it('does not call the API', () => {
|
||||
rolesToSelect.at(1).setSelected()
|
||||
// TODO: Fix this
|
||||
expect(apolloMutateMock).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('new role', () => {
|
||||
describe('new role "USER"', () => {
|
||||
beforeEach(() => {
|
||||
rolesToSelect.at(0).setSelected()
|
||||
})
|
||||
@ -287,19 +537,90 @@ describe('ChangeUserRoleFormular', () => {
|
||||
mutation: setUserRole,
|
||||
variables: {
|
||||
userId: 1,
|
||||
isAdmin: false,
|
||||
role: 'USER',
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('emits "updateIsAdmin"', () => {
|
||||
expect(wrapper.emitted('updateIsAdmin')).toEqual(
|
||||
it('emits "updateRoles"', () => {
|
||||
expect(wrapper.emitted('updateRoles')).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.arrayContaining([
|
||||
{
|
||||
userId: 1,
|
||||
isAdmin: null,
|
||||
roles: [],
|
||||
},
|
||||
]),
|
||||
]),
|
||||
)
|
||||
})
|
||||
|
||||
it('toasts success message', () => {
|
||||
expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo')
|
||||
})
|
||||
})
|
||||
|
||||
describe('confirm role change with error', () => {
|
||||
beforeEach(async () => {
|
||||
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
|
||||
apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
|
||||
await wrapper.find('button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
})
|
||||
|
||||
it('toasts an error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('new role "MODERATOR"', () => {
|
||||
beforeEach(() => {
|
||||
rolesToSelect.at(1).setSelected()
|
||||
})
|
||||
|
||||
it('has "change_user_role" button enabled', () => {
|
||||
expect(wrapper.find('button.btn.btn-danger').exists()).toBe(true)
|
||||
expect(wrapper.find('button.btn.btn-danger[disabled="disabled"]').exists()).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
describe('clicking the "change_user_role" button', () => {
|
||||
beforeEach(async () => {
|
||||
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
|
||||
spy.mockImplementation(() => Promise.resolve(true))
|
||||
await wrapper.find('button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
})
|
||||
|
||||
it('calls the modal', () => {
|
||||
expect(wrapper.emitted('showModal'))
|
||||
expect(spy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
describe('confirm role change with success', () => {
|
||||
it('calls the API', () => {
|
||||
expect(apolloMutateMock).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
mutation: setUserRole,
|
||||
variables: {
|
||||
userId: 1,
|
||||
role: 'MODERATOR',
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('emits "updateRoles"', () => {
|
||||
expect(wrapper.emitted('updateRoles')).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.arrayContaining([
|
||||
{
|
||||
userId: 1,
|
||||
roles: ['MODERATOR'],
|
||||
},
|
||||
]),
|
||||
]),
|
||||
@ -328,5 +649,23 @@ describe('ChangeUserRoleFormular', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('authenticated user is MODERATOR', () => {
|
||||
beforeEach(() => {
|
||||
mocks.$store.state.moderator.roles = ['MODERATOR']
|
||||
})
|
||||
|
||||
it('displays text with role', () => {
|
||||
expect(wrapper.text()).toBe('userRole.selectRoles.admin')
|
||||
})
|
||||
|
||||
it('has no role select', () => {
|
||||
expect(wrapper.find('select.role-select').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('has no button', () => {
|
||||
expect(wrapper.find('button.btn.btn-dange').exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<div class="change-user-role-formular">
|
||||
<div class="shadow p-3 mb-5 bg-white rounded">
|
||||
<div v-if="item.userId === $store.state.moderator.id" class="m-3 mb-4">
|
||||
<div v-if="!$store.state.moderator.roles.includes('ADMIN')" class="m-3 mb-4">
|
||||
{{ roles.find((role) => role.value === currentRole).text }}
|
||||
</div>
|
||||
<div v-else-if="item.userId === $store.state.moderator.id" class="m-3 mb-4">
|
||||
{{ $t('userRole.notChangeYourSelf') }}
|
||||
</div>
|
||||
<div v-else class="m-3">
|
||||
@ -25,8 +28,9 @@
|
||||
import { setUserRole } from '../graphql/setUserRole'
|
||||
|
||||
const rolesValues = {
|
||||
admin: 'admin',
|
||||
user: 'user',
|
||||
ADMIN: 'ADMIN',
|
||||
MODERATOR: 'MODERATOR',
|
||||
USER: 'USER',
|
||||
}
|
||||
|
||||
export default {
|
||||
@ -39,23 +43,30 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentRole: this.item.isAdmin ? rolesValues.admin : rolesValues.user,
|
||||
roleSelected: this.item.isAdmin ? rolesValues.admin : rolesValues.user,
|
||||
currentRole: this.getCurrentRole(),
|
||||
roleSelected: this.getCurrentRole(),
|
||||
roles: [
|
||||
{ value: rolesValues.user, text: this.$t('userRole.selectRoles.user') },
|
||||
{ value: rolesValues.admin, text: this.$t('userRole.selectRoles.admin') },
|
||||
{ value: rolesValues.USER, text: this.$t('userRole.selectRoles.user') },
|
||||
{ value: rolesValues.MODERATOR, text: this.$t('userRole.selectRoles.moderator') },
|
||||
{ value: rolesValues.ADMIN, text: this.$t('userRole.selectRoles.admin') },
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCurrentRole() {
|
||||
if (this.item.roles.length) return rolesValues[this.item.roles[0]]
|
||||
return rolesValues.USER
|
||||
},
|
||||
showModal() {
|
||||
this.$bvModal
|
||||
.msgBoxConfirm(
|
||||
this.$t('overlay.changeUserRole.question', {
|
||||
username: `${this.item.firstName} ${this.item.lastName}`,
|
||||
newRole:
|
||||
this.roleSelected === 'admin'
|
||||
this.roleSelected === rolesValues.ADMIN
|
||||
? this.$t('userRole.selectRoles.admin')
|
||||
: this.roleSelected === rolesValues.MODERATOR
|
||||
? this.$t('userRole.selectRoles.moderator')
|
||||
: this.$t('userRole.selectRoles.user'),
|
||||
}),
|
||||
{
|
||||
@ -77,25 +88,27 @@ export default {
|
||||
})
|
||||
},
|
||||
setUserRole(newRole, oldRole) {
|
||||
const role = this.roles.find((role) => {
|
||||
return role.value === newRole
|
||||
})
|
||||
const roleText = role.text
|
||||
const roleValue = role.value
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: setUserRole,
|
||||
variables: {
|
||||
userId: this.item.userId,
|
||||
isAdmin: newRole === rolesValues.admin,
|
||||
role: role.value,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
this.$emit('updateIsAdmin', {
|
||||
this.$emit('updateRoles', {
|
||||
userId: this.item.userId,
|
||||
isAdmin: result.data.setUserRole,
|
||||
roles: roleValue === 'USER' ? [] : [roleValue],
|
||||
})
|
||||
this.toastSuccess(
|
||||
this.$t('userRole.successfullyChangedTo', {
|
||||
role:
|
||||
result.data.setUserRole !== null
|
||||
? this.$t('userRole.selectRoles.admin')
|
||||
: this.$t('userRole.selectRoles.user'),
|
||||
role: roleText,
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
@ -15,6 +15,7 @@ const propsData = {
|
||||
email: 'bibi@bloxberg.de',
|
||||
creation: [200, 400, 600],
|
||||
emailChecked: true,
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
userId: 2,
|
||||
@ -23,6 +24,7 @@ const propsData = {
|
||||
email: 'benjamin@bluemchen.de',
|
||||
creation: [1000, 1000, 1000],
|
||||
emailChecked: true,
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
userId: 3,
|
||||
@ -31,6 +33,7 @@ const propsData = {
|
||||
email: 'peter@lustig.de',
|
||||
creation: [0, 0, 0],
|
||||
emailChecked: true,
|
||||
roles: ['ADMIN'],
|
||||
},
|
||||
{
|
||||
userId: 4,
|
||||
@ -39,6 +42,7 @@ const propsData = {
|
||||
email: 'new@user.ch',
|
||||
creation: [1000, 1000, 1000],
|
||||
emailChecked: false,
|
||||
roles: [],
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
@ -68,6 +72,7 @@ const mocks = {
|
||||
moderator: {
|
||||
id: 0,
|
||||
name: 'test moderator',
|
||||
roles: ['ADMIN'],
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -96,14 +101,14 @@ describe('SearchUserTable', () => {
|
||||
|
||||
describe('isAdmin', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.find('div.change-user-role-formular').vm.$emit('updateIsAdmin', {
|
||||
await wrapper.find('div.change-user-role-formular').vm.$emit('updateRoles', {
|
||||
userId: 1,
|
||||
isAdmin: new Date(),
|
||||
roles: ['ADMIN'],
|
||||
})
|
||||
})
|
||||
|
||||
it('emits updateIsAdmin', () => {
|
||||
expect(wrapper.emitted('updateIsAdmin')).toEqual([[1, expect.any(Date)]])
|
||||
expect(wrapper.emitted('updateRoles')).toEqual([[1, ['ADMIN']]])
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -79,9 +79,9 @@
|
||||
<transaction-link-list v-if="!row.item.deletedAt" :userId="row.item.userId" />
|
||||
</b-tab>
|
||||
<b-tab :title="$t('userRole.tabTitle')">
|
||||
<change-user-role-formular :item="row.item" @updateIsAdmin="updateIsAdmin" />
|
||||
<change-user-role-formular :item="row.item" @updateRoles="updateRoles" />
|
||||
</b-tab>
|
||||
<b-tab :title="$t('delete_user')">
|
||||
<b-tab v-if="$store.state.moderator.roles.includes('ADMIN')" :title="$t('delete_user')">
|
||||
<deleted-user-formular :item="row.item" @updateDeletedAt="updateDeletedAt" />
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
@ -127,8 +127,8 @@ export default {
|
||||
updateUserData(rowItem, newCreation) {
|
||||
rowItem.creation = newCreation
|
||||
},
|
||||
updateIsAdmin({ userId, isAdmin }) {
|
||||
this.$emit('updateIsAdmin', userId, isAdmin)
|
||||
updateRoles({ userId, roles }) {
|
||||
this.$emit('updateRoles', userId, roles)
|
||||
},
|
||||
updateDeletedAt({ userId, deletedAt }) {
|
||||
this.$emit('updateDeletedAt', userId, deletedAt)
|
||||
|
||||
47
admin/src/components/UserQuery.spec.js
Normal file
47
admin/src/components/UserQuery.spec.js
Normal file
@ -0,0 +1,47 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import UserQuery from './UserQuery'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const propsData = {
|
||||
userId: 42,
|
||||
}
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
}
|
||||
describe('TransactionLinkList', () => {
|
||||
let wrapper
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(UserQuery, { mocks, localVue, propsData })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('has div .input-group', () => {
|
||||
expect(wrapper.find('div .input-group').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('has .test-input-criteria', () => {
|
||||
expect(wrapper.find('input.test-input-criteria').exists()).toBe(true)
|
||||
})
|
||||
|
||||
describe('set value', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
await wrapper.find('input.test-input-criteria').setValue('Test2')
|
||||
})
|
||||
|
||||
it('emits input', () => {
|
||||
expect(wrapper.emitted('input')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('emits input with value "Test2"', () => {
|
||||
expect(wrapper.emitted('input')).toEqual([['Test2']])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -26,7 +26,7 @@ export const searchUsers = gql`
|
||||
hasElopage
|
||||
emailConfirmationSend
|
||||
deletedAt
|
||||
isAdmin
|
||||
roles
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const setUserRole = gql`
|
||||
mutation ($userId: Int!, $isAdmin: Boolean!) {
|
||||
setUserRole(userId: $userId, isAdmin: $isAdmin)
|
||||
mutation ($userId: Int!, $role: RoleNames!) {
|
||||
setUserRole(userId: $userId, role: $role)
|
||||
}
|
||||
`
|
||||
|
||||
@ -5,7 +5,7 @@ export const verifyLogin = gql`
|
||||
verifyLogin {
|
||||
firstName
|
||||
lastName
|
||||
isAdmin
|
||||
roles
|
||||
id
|
||||
language
|
||||
}
|
||||
|
||||
@ -209,6 +209,7 @@
|
||||
"selectLabel": "Rolle:",
|
||||
"selectRoles": {
|
||||
"admin": "Administrator",
|
||||
"moderator": "Moderator",
|
||||
"user": "einfacher Nutzer"
|
||||
},
|
||||
"successfullyChangedTo": "Nutzer ist jetzt „{role}“.",
|
||||
|
||||
@ -209,6 +209,7 @@
|
||||
"selectLabel": "Role:",
|
||||
"selectRoles": {
|
||||
"admin": "administrator",
|
||||
"moderator": "moderator",
|
||||
"user": "usual user"
|
||||
},
|
||||
"successfullyChangedTo": "User is now \"{role}\".",
|
||||
|
||||
@ -28,7 +28,7 @@ const mocks = {
|
||||
moderator: {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
isAdmin: '2022-08-30T07:41:31.000Z',
|
||||
roles: ['ADMIN'],
|
||||
id: 263,
|
||||
language: 'de',
|
||||
},
|
||||
|
||||
@ -16,6 +16,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||
email: 'new@user.ch',
|
||||
creation: [1000, 1000, 1000],
|
||||
emailChecked: false,
|
||||
roles: [],
|
||||
deletedAt: null,
|
||||
},
|
||||
{
|
||||
@ -24,6 +25,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||
lastName: 'Lustig',
|
||||
email: 'peter@lustig.de',
|
||||
creation: [0, 0, 0],
|
||||
roles: ['ADMIN'],
|
||||
emailChecked: true,
|
||||
deletedAt: null,
|
||||
},
|
||||
@ -33,6 +35,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||
lastName: 'Blümchen',
|
||||
email: 'benjamin@bluemchen.de',
|
||||
creation: [1000, 1000, 1000],
|
||||
roles: [],
|
||||
emailChecked: true,
|
||||
deletedAt: new Date(),
|
||||
},
|
||||
@ -42,6 +45,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||
lastName: 'Bloxberg',
|
||||
email: 'bibi@bloxberg.de',
|
||||
creation: [200, 400, 600],
|
||||
roles: [],
|
||||
emailChecked: true,
|
||||
deletedAt: null,
|
||||
},
|
||||
@ -212,10 +216,10 @@ describe('UserSearch', () => {
|
||||
it('updates user role to admin', async () => {
|
||||
await wrapper
|
||||
.findComponent({ name: 'SearchUserTable' })
|
||||
.vm.$emit('updateIsAdmin', userId, new Date())
|
||||
expect(wrapper.vm.searchResult.find((obj) => obj.userId === userId).isAdmin).toEqual(
|
||||
expect.any(Date),
|
||||
)
|
||||
.vm.$emit('updateRoles', userId, ['ADMIN'])
|
||||
expect(wrapper.vm.searchResult.find((obj) => obj.userId === userId).roles).toEqual([
|
||||
'ADMIN',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@ -223,8 +227,8 @@ describe('UserSearch', () => {
|
||||
it('updates user role to usual user', async () => {
|
||||
await wrapper
|
||||
.findComponent({ name: 'SearchUserTable' })
|
||||
.vm.$emit('updateIsAdmin', userId, null)
|
||||
expect(wrapper.vm.searchResult.find((obj) => obj.userId === userId).isAdmin).toEqual(null)
|
||||
.vm.$emit('updateRoles', userId, [])
|
||||
expect(wrapper.vm.searchResult.find((obj) => obj.userId === userId).roles).toEqual([])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
type="PageUserSearch"
|
||||
:items="searchResult"
|
||||
:fields="fields"
|
||||
@updateIsAdmin="updateIsAdmin"
|
||||
@updateRoles="updateRoles"
|
||||
@updateDeletedAt="updateDeletedAt"
|
||||
/>
|
||||
<b-pagination
|
||||
@ -101,8 +101,8 @@ export default {
|
||||
this.toastError(error.message)
|
||||
})
|
||||
},
|
||||
updateIsAdmin(userId, isAdmin) {
|
||||
this.searchResult.find((obj) => obj.userId === userId).isAdmin = isAdmin
|
||||
updateRoles(userId, roles) {
|
||||
this.searchResult.find((obj) => obj.userId === userId).roles = roles
|
||||
},
|
||||
updateDeletedAt(userId, deletedAt) {
|
||||
this.searchResult.find((obj) => obj.userId === userId).deletedAt = deletedAt
|
||||
|
||||
@ -13,7 +13,7 @@ const addNavigationGuards = (router, store, apollo, i18n) => {
|
||||
})
|
||||
.then((result) => {
|
||||
const moderator = result.data.verifyLogin
|
||||
if (moderator.isAdmin) {
|
||||
if (moderator.roles?.length) {
|
||||
i18n.locale = moderator.language
|
||||
store.commit('moderator', moderator)
|
||||
next({ path: '/' })
|
||||
@ -35,7 +35,7 @@ const addNavigationGuards = (router, store, apollo, i18n) => {
|
||||
!CONFIG.DEBUG_DISABLE_AUTH && // we did not disabled the auth module for debug purposes
|
||||
(!store.state.token || // we do not have a token
|
||||
!store.state.moderator || // no moderator set in store
|
||||
!store.state.moderator.isAdmin) && // user is no admin
|
||||
!store.state.moderator.roles.length) && // user is no admin
|
||||
to.path !== '/not-found' && // we are not on `not-found`
|
||||
to.path !== '/logout' // we are not on `logout`
|
||||
) {
|
||||
|
||||
@ -5,7 +5,7 @@ const storeCommitMock = jest.fn()
|
||||
const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
verifyLogin: {
|
||||
isAdmin: true,
|
||||
roles: ['ADMIN'],
|
||||
language: 'de',
|
||||
},
|
||||
},
|
||||
@ -52,7 +52,10 @@ describe('navigation guards', () => {
|
||||
})
|
||||
|
||||
it('commits the moderator to the store', () => {
|
||||
expect(storeCommitMock).toBeCalledWith('moderator', { isAdmin: true, language: 'de' })
|
||||
expect(storeCommitMock).toBeCalledWith('moderator', {
|
||||
roles: ['ADMIN'],
|
||||
language: 'de',
|
||||
})
|
||||
})
|
||||
|
||||
it('redirects to /', () => {
|
||||
@ -60,12 +63,48 @@ describe('navigation guards', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('with valid token and not as admin', () => {
|
||||
beforeEach(() => {
|
||||
describe('with valid token and as moderator', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
apolloQueryMock.mockResolvedValue({
|
||||
data: {
|
||||
verifyLogin: {
|
||||
isAdmin: false,
|
||||
roles: ['MODERATOR'],
|
||||
language: 'de',
|
||||
},
|
||||
},
|
||||
})
|
||||
await navGuard({ path: '/authenticate', query: { token: 'valid-token' } }, {}, next)
|
||||
})
|
||||
|
||||
it('commits the token to the store', () => {
|
||||
expect(storeCommitMock).toBeCalledWith('token', 'valid-token')
|
||||
})
|
||||
|
||||
it.skip('sets the locale', () => {
|
||||
expect(i18nLocaleMock).toBeCalledWith('de')
|
||||
})
|
||||
|
||||
it('commits the moderator to the store', () => {
|
||||
expect(storeCommitMock).toBeCalledWith('moderator', {
|
||||
roles: ['MODERATOR'],
|
||||
language: 'de',
|
||||
})
|
||||
})
|
||||
|
||||
it('redirects to /', () => {
|
||||
expect(next).toBeCalledWith({ path: '/' })
|
||||
})
|
||||
})
|
||||
|
||||
describe('with valid token and no roles', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
apolloQueryMock.mockResolvedValue({
|
||||
data: {
|
||||
verifyLogin: {
|
||||
roles: [],
|
||||
language: 'de',
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -77,7 +116,7 @@ describe('navigation guards', () => {
|
||||
})
|
||||
|
||||
it('does not commit the moderator to the store', () => {
|
||||
expect(storeCommitMock).not.toBeCalledWith('moderator', { isAdmin: false })
|
||||
expect(storeCommitMock).not.toBeCalledWith('moderator')
|
||||
})
|
||||
|
||||
it('redirects to /not-found', async () => {
|
||||
@ -128,15 +167,22 @@ describe('navigation guards', () => {
|
||||
expect(next).toBeCalledWith({ path: '/not-found' })
|
||||
})
|
||||
|
||||
it('redirects to not found with token in store and not moderator', () => {
|
||||
it('redirects to not found with token in store and not admin or moderator', () => {
|
||||
store.state.token = 'valid token'
|
||||
navGuard({ path: '/' }, {}, next)
|
||||
expect(next).toBeCalledWith({ path: '/not-found' })
|
||||
})
|
||||
|
||||
it('does not redirect with token in store and as admin', () => {
|
||||
store.state.token = 'valid token'
|
||||
store.state.moderator = { roles: ['ADMIN'] }
|
||||
navGuard({ path: '/' }, {}, next)
|
||||
expect(next).toBeCalledWith()
|
||||
})
|
||||
|
||||
it('does not redirect with token in store and as moderator', () => {
|
||||
store.state.token = 'valid token'
|
||||
store.state.moderator = { isAdmin: true }
|
||||
store.state.moderator = { roles: ['MODERATOR'] }
|
||||
navGuard({ path: '/' }, {}, next)
|
||||
expect(next).toBeCalledWith()
|
||||
})
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gradido-backend",
|
||||
"version": "1.22.3",
|
||||
"version": "1.23.0",
|
||||
"description": "Gradido unified backend providing an API-Service for Gradido Transactions",
|
||||
"main": "src/index.ts",
|
||||
"repository": "https://github.com/gradido/gradido/backend",
|
||||
|
||||
@ -655,9 +655,7 @@ export class UserResolver {
|
||||
const clientTimezoneOffset = getClientTimezoneOffset(context)
|
||||
const userFields = ['id', 'firstName', 'lastName', 'emailId', 'emailContact', 'deletedAt']
|
||||
const [users, count] = await findUsers(
|
||||
userFields.map((fieldName) => {
|
||||
return 'user.' + fieldName
|
||||
}),
|
||||
userFields,
|
||||
query,
|
||||
filters ?? null,
|
||||
currentPage,
|
||||
|
||||
@ -1,10 +1,24 @@
|
||||
import { getConnection, Brackets, IsNull, Not } from '@dbTools/typeorm'
|
||||
import { IsNull, Not, Like } from '@dbTools/typeorm'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
|
||||
import { SearchUsersFilters } from '@arg/SearchUsersFilters'
|
||||
import { Order } from '@enum/Order'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
function likeQuery(searchCriteria: string) {
|
||||
return Like(`%${searchCriteria}%`)
|
||||
}
|
||||
|
||||
function emailCheckedQuery(filters: SearchUsersFilters) {
|
||||
return filters.byActivated ?? undefined
|
||||
}
|
||||
|
||||
function deletedAtQuery(filters: SearchUsersFilters | null) {
|
||||
return filters?.byDeleted !== undefined && filters?.byDeleted !== null
|
||||
? filters.byDeleted
|
||||
? Not(IsNull())
|
||||
: IsNull()
|
||||
: undefined
|
||||
}
|
||||
|
||||
export const findUsers = async (
|
||||
select: string[],
|
||||
@ -14,44 +28,51 @@ export const findUsers = async (
|
||||
pageSize: number,
|
||||
order = Order.ASC,
|
||||
): Promise<[DbUser[], number]> => {
|
||||
const queryRunner = getConnection().createQueryRunner()
|
||||
try {
|
||||
await queryRunner.connect()
|
||||
const query = queryRunner.manager
|
||||
.createQueryBuilder(DbUser, 'user')
|
||||
.select(select)
|
||||
.withDeleted()
|
||||
.leftJoinAndSelect('user.emailContact', 'emailContact')
|
||||
.where(
|
||||
new Brackets((qb) => {
|
||||
qb.where(
|
||||
'user.firstName like :name or user.lastName like :lastName or emailContact.email like :email',
|
||||
{
|
||||
name: `%${searchCriteria}%`,
|
||||
lastName: `%${searchCriteria}%`,
|
||||
email: `%${searchCriteria}%`,
|
||||
},
|
||||
)
|
||||
}),
|
||||
)
|
||||
if (filters) {
|
||||
if (filters.byActivated !== null) {
|
||||
query.andWhere('emailContact.emailChecked = :value', { value: filters.byActivated })
|
||||
}
|
||||
|
||||
if (filters.byDeleted !== null) {
|
||||
query.andWhere({ deletedAt: filters.byDeleted ? Not(IsNull()) : IsNull() })
|
||||
}
|
||||
}
|
||||
|
||||
return await query
|
||||
.orderBy({ 'user.id': order })
|
||||
.take(pageSize)
|
||||
.skip((currentPage - 1) * pageSize)
|
||||
.getManyAndCount()
|
||||
} catch (err) {
|
||||
throw new LogError('Unable to search users', err)
|
||||
} finally {
|
||||
await queryRunner.release()
|
||||
const where = [
|
||||
{
|
||||
firstName: likeQuery(searchCriteria),
|
||||
deletedAt: deletedAtQuery(filters),
|
||||
emailContact: filters
|
||||
? {
|
||||
emailChecked: emailCheckedQuery(filters),
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
lastName: likeQuery(searchCriteria),
|
||||
deletedAt: deletedAtQuery(filters),
|
||||
emailContact: filters
|
||||
? {
|
||||
emailChecked: emailCheckedQuery(filters),
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
emailContact: {
|
||||
// ...(filters ?? emailChecked: filters.byActivated)
|
||||
emailChecked: filters ? emailCheckedQuery(filters) : undefined,
|
||||
email: likeQuery(searchCriteria),
|
||||
},
|
||||
deletedAt: deletedAtQuery(filters),
|
||||
},
|
||||
]
|
||||
const selectFind = Object.fromEntries(select.map((item) => [item, true]))
|
||||
const relations = ['emailContact', 'userRoles']
|
||||
const orderFind = {
|
||||
id: order,
|
||||
}
|
||||
const take = pageSize
|
||||
const skip = (currentPage - 1) * pageSize
|
||||
const withDeleted = true
|
||||
|
||||
const [users, count] = await DbUser.findAndCount({
|
||||
where,
|
||||
withDeleted,
|
||||
select: selectFind,
|
||||
relations,
|
||||
order: orderFind,
|
||||
take,
|
||||
skip,
|
||||
})
|
||||
return [users, count]
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
|
||||
await queryFn(`
|
||||
INSERT INTO user_roles
|
||||
(user_id, role, created_at, updated_at)
|
||||
SELECT u.id, 'admin', u.is_admin, null
|
||||
SELECT u.id, 'ADMIN', u.is_admin, null
|
||||
FROM users u
|
||||
WHERE u.is_admin IS NOT NULL;`)
|
||||
|
||||
@ -31,7 +31,7 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom
|
||||
)
|
||||
// reconstruct the previous is_admin back from user_roles to users table
|
||||
const roles = await queryFn(
|
||||
`SELECT r.user_id, r.role, r.created_at FROM user_roles as r WHERE r.role = "admin"`,
|
||||
`SELECT r.user_id, r.role, r.created_at FROM user_roles as r WHERE r.role = "ADMIN"`,
|
||||
)
|
||||
for (const id in roles) {
|
||||
const role = roles[id]
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gradido-database",
|
||||
"version": "1.22.3",
|
||||
"version": "1.23.0",
|
||||
"description": "Gradido Database Tool to execute database migrations",
|
||||
"main": "src/index.ts",
|
||||
"repository": "https://github.com/gradido/gradido/database",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gradido-dht-node",
|
||||
"version": "1.22.3",
|
||||
"version": "1.23.0",
|
||||
"description": "Gradido dht-node module",
|
||||
"main": "src/index.ts",
|
||||
"repository": "https://github.com/gradido/gradido/",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gradido-federation",
|
||||
"version": "1.22.3",
|
||||
"version": "1.23.0",
|
||||
"description": "Gradido federation module providing Gradido-Hub-Federation and versioned API for inter community communication",
|
||||
"main": "src/index.ts",
|
||||
"repository": "https://github.com/gradido/gradido/federation",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bootstrap-vue-gradido-wallet",
|
||||
"version": "1.22.3",
|
||||
"version": "1.23.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node run/server.js",
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
</b-nav-item>
|
||||
<b-nav-item
|
||||
class="mb-3 text-light"
|
||||
v-if="$store.state.roles.length > 0"
|
||||
v-if="$store.state.roles && $store.state.roles.length > 0"
|
||||
@click="$emit('admin')"
|
||||
active-class="activeRoute"
|
||||
>
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
"myContributions": "Meine Beiträge",
|
||||
"noOpenContributionLinkText": "Zur Zeit gibt es keine per Link erzeugte Schöpfungen.",
|
||||
"openContributionLinks": "Per Link erzeugte Schöpfungen",
|
||||
"openContributionLinkText": "Die Gemeinschaft „{name}“ unterstützt aktuell {count} per Link erzeugte Schöpfungen:",
|
||||
"openContributionLinkText": "Für Startguthaben oder ähnliche Zwecke kann die Gemeinschaft so genannte Schöpfungs-Links erstellen. Sie lösen automatische Schöpfungen aus, die dem Benutzer gut geschrieben werden.\nDie Gemeinschaft „{name}“ unterstützt aktuell {count} per Link erzeugte Schöpfungen:",
|
||||
"startNewsButton": "Benutzernamen eintragen",
|
||||
"submitContribution": "Schreiben"
|
||||
},
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
"myContributions": "My contributions",
|
||||
"noOpenContributionLinkText": "Currently there are no link-generated creations.",
|
||||
"openContributionLinks": "Creations generated by link",
|
||||
"openContributionLinkText": "The \"{name}\" community currently supports {count} link-generated creations:",
|
||||
"openContributionLinkText": "For starting credits or similar purposes, the community can create so-called creation links. They trigger automatic creations that are credited to the user.\nThe \"{name}\" community currently supports {count} link-generated creations:",
|
||||
"startNewsButton": "Enter username",
|
||||
"submitContribution": "Contribute"
|
||||
},
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
"myContributions": "Mis contribuciones al bien común",
|
||||
"noOpenContributionLinkText": "Actualmente no hay creaciones generadas por enlaces.",
|
||||
"openContributionLinks": "Creaciones generadas por enlace",
|
||||
"openContributionLinkText": "La comunidad \"{name}\" admite actualmente {count} creaciones generadas por enlaces:",
|
||||
"openContributionLinkText": "Para créditos iniciales o fines similares, la comunidad puede crear los llamados enlaces de creación. Éstos activan creaciones automáticas que se acreditan al usuario.\nLa comunidad \"{name}\" admite actualmente {count} creaciones generadas por enlaces:",
|
||||
"other-communities": "Otras comunidades",
|
||||
"startNewsButton": "Introducir nombre de usuario",
|
||||
"statistic": "Estadísticas",
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
"myContributions": "Mes contributions",
|
||||
"noOpenContributionLinkText": "Actuellement, il n'y a pas de créations générées par lien.",
|
||||
"openContributionLinks": "Créations générées par lien",
|
||||
"openContributionLinkText": "La communauté \"{name}\" soutient actuellement {count} créations générées par lien:",
|
||||
"openContributionLinkText": "Pour les crédits de départ ou à des fins similaires, la communauté peut créer des \"liens de création\". Ils déclenchent des créations automatiques qui sont créditées à l'utilisateur.\nLa communauté \"{name}\" soutient actuellement {count} créations générées par lien:",
|
||||
"startNewsButton": "Saisir nom d'utilisateur",
|
||||
"submitContribution": "Contribuer"
|
||||
},
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
"myContributions": "Mijn bijdragen voor het algemeen belang",
|
||||
"noOpenContributionLinkText": "Er zijn momenteel geen link-gegenereerde creaties.",
|
||||
"openContributionLinks": "Creaties gegenereerd door link",
|
||||
"openContributionLinkText": "De community \"{name}\" ondersteunt momenteel {count} link-gegenereerde creaties:",
|
||||
"openContributionLinkText": "Voor startcredits of soortgelijke doeleinden kan de community zogenaamde creatielinks maken. Deze activeren automatische creaties die worden gecrediteerd aan de gebruiker.\nDe community \"{name}\" ondersteunt momenteel {count} link-gegenereerde creaties:",
|
||||
"other-communities": "Verdere gemeenschappen",
|
||||
"startNewsButton": "Gebruikersnaam invoeren",
|
||||
"statistic": "Statistieken",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gradido",
|
||||
"version": "1.22.3",
|
||||
"version": "1.23.0",
|
||||
"description": "Gradido",
|
||||
"main": "index.js",
|
||||
"repository": "git@github.com:gradido/gradido.git",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user