mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
Merge pull request #3311 from gradido/humhub_login_link
feat(frontend): auto-login link for humhub
This commit is contained in:
commit
0c1b88e9ca
@ -7,7 +7,7 @@ module.exports = {
|
||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
lines: 82,
|
||||
lines: 81,
|
||||
},
|
||||
},
|
||||
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { User as dbUser } from '@entity/User'
|
||||
|
||||
import { GmsPublishLocationType } from '@/graphql/enum/GmsPublishLocationType'
|
||||
import { GmsPublishNameType } from '@/graphql/enum/GmsPublishNameType'
|
||||
import { GmsPublishPhoneType } from '@/graphql/enum/GmsPublishPhoneType'
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
|
||||
export class GmsUser {
|
||||
constructor(user: dbUser) {
|
||||
@ -44,7 +44,7 @@ export class GmsUser {
|
||||
if (
|
||||
user.gmsAllowed &&
|
||||
user.alias &&
|
||||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS
|
||||
user.gmsPublishName === PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS
|
||||
) {
|
||||
return user.alias
|
||||
}
|
||||
@ -53,32 +53,30 @@ export class GmsUser {
|
||||
private getGmsFirstName(user: dbUser): string | undefined {
|
||||
if (
|
||||
user.gmsAllowed &&
|
||||
(user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_FIRST ||
|
||||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_FIRST_INITIAL ||
|
||||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_FULL)
|
||||
(user.gmsPublishName === PublishNameType.PUBLISH_NAME_FIRST ||
|
||||
user.gmsPublishName === PublishNameType.PUBLISH_NAME_FIRST_INITIAL ||
|
||||
user.gmsPublishName === PublishNameType.PUBLISH_NAME_FULL)
|
||||
) {
|
||||
return user.firstName
|
||||
}
|
||||
if (
|
||||
user.gmsAllowed &&
|
||||
((!user.alias &&
|
||||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS) ||
|
||||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_INITIALS)
|
||||
((!user.alias && user.gmsPublishName === PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS) ||
|
||||
user.gmsPublishName === PublishNameType.PUBLISH_NAME_INITIALS)
|
||||
) {
|
||||
return user.firstName.substring(0, 1)
|
||||
}
|
||||
}
|
||||
|
||||
private getGmsLastName(user: dbUser): string | undefined {
|
||||
if (user.gmsAllowed && user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_FULL) {
|
||||
if (user.gmsAllowed && user.gmsPublishName === PublishNameType.PUBLISH_NAME_FULL) {
|
||||
return user.lastName
|
||||
}
|
||||
if (
|
||||
user.gmsAllowed &&
|
||||
((!user.alias &&
|
||||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS) ||
|
||||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_FIRST_INITIAL ||
|
||||
user.gmsPublishName === GmsPublishNameType.GMS_PUBLISH_NAME_INITIALS)
|
||||
((!user.alias && user.gmsPublishName === PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS) ||
|
||||
user.gmsPublishName === PublishNameType.PUBLISH_NAME_FIRST_INITIAL ||
|
||||
user.gmsPublishName === PublishNameType.PUBLISH_NAME_INITIALS)
|
||||
) {
|
||||
return user.lastName.substring(0, 1)
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { SignJWT } from 'jose'
|
||||
import { IRequestOptions, RestClient } from 'typed-rest-client'
|
||||
import { IRequestOptions, IRestResponse, RestClient } from 'typed-rest-client'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
|
||||
import { PostUserLoggingView } from './logging/PostUserLogging.view'
|
||||
import { GetUser } from './model/GetUser'
|
||||
import { PostUser } from './model/PostUser'
|
||||
import { UsersResponse } from './model/UsersResponse'
|
||||
@ -58,6 +59,18 @@ export class HumHubClient {
|
||||
return token
|
||||
}
|
||||
|
||||
public async createAutoLoginUrl(username: string) {
|
||||
const secret = new TextEncoder().encode(CONFIG.HUMHUB_JWT_KEY)
|
||||
logger.info(`user ${username} as username for humhub auto-login`)
|
||||
const token = await new SignJWT({ username })
|
||||
.setProtectedHeader({ alg: 'HS256' })
|
||||
.setIssuedAt()
|
||||
.setExpirationTime('2m')
|
||||
.sign(secret)
|
||||
|
||||
return `${CONFIG.HUMHUB_API_URL}user/auth/external?authclient=jwt&jwt=${token}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all users from humhub
|
||||
* https://marketplace.humhub.com/module/rest/docs/html/user.html#tag/User/paths/~1user/get
|
||||
@ -90,12 +103,38 @@ export class HumHubClient {
|
||||
return response.result
|
||||
}
|
||||
|
||||
public async userByEmailAsync(email: string): Promise<IRestResponse<GetUser>> {
|
||||
const options = await this.createRequestOptions({ email })
|
||||
return this.restClient.get<GetUser>('/api/v1/user/get-by-email', options)
|
||||
}
|
||||
|
||||
public async userByUsernameAsync(username: string): Promise<IRestResponse<GetUser>> {
|
||||
const options = await this.createRequestOptions({ username })
|
||||
return this.restClient.get<GetUser>('/api/v1/user/get-by-username', options)
|
||||
}
|
||||
|
||||
/**
|
||||
* get user by username
|
||||
* https://marketplace.humhub.com/module/rest/docs/html/user.html#tag/User/paths/~1user~1get-by-username/get
|
||||
* @param username for user search
|
||||
* @returns user object if found
|
||||
*/
|
||||
public async userByUsername(username: string): Promise<GetUser | null> {
|
||||
const options = await this.createRequestOptions({ username })
|
||||
const response = await this.restClient.get<GetUser>('/api/v1/user/get-by-username', options)
|
||||
if (response.statusCode === 404) {
|
||||
return null
|
||||
}
|
||||
return response.result
|
||||
}
|
||||
|
||||
/**
|
||||
* create user
|
||||
* https://marketplace.humhub.com/module/rest/docs/html/user.html#tag/User/paths/~1user/post
|
||||
* @param user for saving on humhub instance
|
||||
*/
|
||||
public async createUser(user: PostUser): Promise<void> {
|
||||
logger.info('create new humhub user', new PostUserLoggingView(user))
|
||||
const options = await this.createRequestOptions()
|
||||
try {
|
||||
const response = await this.restClient.create('/api/v1/user', user, options)
|
||||
@ -118,6 +157,7 @@ export class HumHubClient {
|
||||
* @returns updated user object on success
|
||||
*/
|
||||
public async updateUser(user: PostUser, humhubUserId: number): Promise<GetUser | null> {
|
||||
logger.info('update humhub user', new PostUserLoggingView(user))
|
||||
const options = await this.createRequestOptions()
|
||||
const response = await this.restClient.update<GetUser>(
|
||||
`/api/v1/user/${humhubUserId}`,
|
||||
@ -133,6 +173,7 @@ export class HumHubClient {
|
||||
}
|
||||
|
||||
public async deleteUser(humhubUserId: number): Promise<void> {
|
||||
logger.info('delete humhub user', { userId: humhubUserId })
|
||||
const options = await this.createRequestOptions()
|
||||
const response = await this.restClient.del(`/api/v1/user/${humhubUserId}`, options)
|
||||
if (response.statusCode === 400) {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { User } from '@entity/User'
|
||||
import { UserContact } from '@entity/UserContact'
|
||||
import { IRestResponse } from 'typed-rest-client'
|
||||
|
||||
import { GetUser } from '@/apis/humhub/model/GetUser'
|
||||
import { PostUser } from '@/apis/humhub/model/PostUser'
|
||||
@ -33,6 +34,25 @@ export class HumHubClient {
|
||||
return Promise.resolve(new GetUser(user, 1))
|
||||
}
|
||||
|
||||
public async userByEmailAsync(email: string): Promise<IRestResponse<GetUser>> {
|
||||
const user = new User()
|
||||
user.emailContact = new UserContact()
|
||||
user.emailContact.email = email
|
||||
return Promise.resolve({
|
||||
statusCode: 200,
|
||||
result: new GetUser(user, 1),
|
||||
headers: {},
|
||||
})
|
||||
}
|
||||
|
||||
public async userByUsername(username: string): Promise<GetUser | null> {
|
||||
const user = new User()
|
||||
user.alias = username
|
||||
user.emailContact = new UserContact()
|
||||
user.emailContact.email = 'testemail@gmail.com'
|
||||
return Promise.resolve(new GetUser(user, 1))
|
||||
}
|
||||
|
||||
public async createUser(): Promise<void> {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ function accountIsTheSame(account: Account, user: User): boolean {
|
||||
if (account.username !== gradidoUserAccount.username) return false
|
||||
if (account.email !== gradidoUserAccount.email) return false
|
||||
if (account.language !== gradidoUserAccount.language) return false
|
||||
if (account.status !== gradidoUserAccount.status) return false
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
18
backend/src/apis/humhub/logging/AccountLogging.view.ts
Normal file
18
backend/src/apis/humhub/logging/AccountLogging.view.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { AbstractLoggingView } from '@logging/AbstractLogging.view'
|
||||
|
||||
import { Account } from '@/apis/humhub/model/Account'
|
||||
|
||||
export class AccountLoggingView extends AbstractLoggingView {
|
||||
public constructor(private self: Account) {
|
||||
super()
|
||||
}
|
||||
|
||||
public toJSON(): Account {
|
||||
return {
|
||||
username: this.self.username.substring(0, 3) + '...',
|
||||
email: this.self.email.substring(0, 3) + '...',
|
||||
language: this.self.language,
|
||||
status: this.self.status,
|
||||
}
|
||||
}
|
||||
}
|
||||
23
backend/src/apis/humhub/logging/PostUserLogging.view.ts
Normal file
23
backend/src/apis/humhub/logging/PostUserLogging.view.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { AbstractLoggingView } from '@logging/AbstractLogging.view'
|
||||
|
||||
import { PostUser } from '@/apis/humhub/model/PostUser'
|
||||
|
||||
import { AccountLoggingView } from './AccountLogging.view'
|
||||
import { ProfileLoggingView } from './ProfileLogging.view'
|
||||
|
||||
export class PostUserLoggingView extends AbstractLoggingView {
|
||||
public constructor(private self: PostUser) {
|
||||
super()
|
||||
}
|
||||
|
||||
public toJSON(): PostUser {
|
||||
return {
|
||||
account: new AccountLoggingView(this.self.account).toJSON(),
|
||||
profile: new ProfileLoggingView(this.self.profile).toJSON(),
|
||||
password: {
|
||||
newPassword: '',
|
||||
mustChangePassword: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
20
backend/src/apis/humhub/logging/ProfileLogging.view.ts
Normal file
20
backend/src/apis/humhub/logging/ProfileLogging.view.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { AbstractLoggingView } from '@logging/AbstractLogging.view'
|
||||
|
||||
import { Profile } from '@/apis/humhub/model/Profile'
|
||||
|
||||
export class ProfileLoggingView extends AbstractLoggingView {
|
||||
public constructor(private self: Profile) {
|
||||
super()
|
||||
}
|
||||
|
||||
public toJSON(): Profile {
|
||||
const gradidoAddressParts = this.self.gradido_address.split('/')
|
||||
return {
|
||||
firstname: this.self.firstname.substring(0, 3) + '...',
|
||||
lastname: this.self.lastname.substring(0, 3) + '...',
|
||||
// eslint-disable-next-line camelcase
|
||||
gradido_address:
|
||||
gradidoAddressParts[0] + '/' + gradidoAddressParts[1].substring(0, 3) + '...',
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
/* eslint-disable camelcase */
|
||||
import { User } from '@entity/User'
|
||||
|
||||
import { convertGradidoLanguageToHumhub } from '@/apis/humhub/convertLanguage'
|
||||
@ -12,9 +13,11 @@ export class Account {
|
||||
|
||||
this.email = user.emailContact.email
|
||||
this.language = convertGradidoLanguageToHumhub(user.language)
|
||||
this.status = 1
|
||||
}
|
||||
|
||||
username: string
|
||||
email: string
|
||||
language: string
|
||||
status: number
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ export enum RIGHTS {
|
||||
OPEN_CREATIONS = 'OPEN_CREATIONS',
|
||||
USER = 'USER',
|
||||
GMS_USER_PLAYGROUND = 'GMS_USER_PLAYGROUND',
|
||||
HUMHUB_AUTO_LOGIN = 'HUMHUB_AUTO_LOGIN',
|
||||
// Moderator
|
||||
SEARCH_USERS = 'SEARCH_USERS',
|
||||
ADMIN_CREATE_CONTRIBUTION = 'ADMIN_CREATE_CONTRIBUTION',
|
||||
|
||||
@ -30,4 +30,5 @@ export const USER_RIGHTS = [
|
||||
RIGHTS.OPEN_CREATIONS,
|
||||
RIGHTS.USER,
|
||||
RIGHTS.GMS_USER_PLAYGROUND,
|
||||
RIGHTS.HUMHUB_AUTO_LOGIN,
|
||||
]
|
||||
|
||||
@ -21,13 +21,16 @@ export class PublishNameLogic {
|
||||
) {
|
||||
return this.user.firstName
|
||||
}
|
||||
if (
|
||||
[PublishNameType.PUBLISH_NAME_INITIALS, PublishNameType.PUBLISH_NAME_INITIAL_LAST].includes(
|
||||
publishNameType,
|
||||
)
|
||||
) {
|
||||
if (PublishNameType.PUBLISH_NAME_INITIALS === publishNameType) {
|
||||
return this.user.firstName.substring(0, 1)
|
||||
}
|
||||
if (PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS === publishNameType) {
|
||||
if (this.user.alias) {
|
||||
return this.user.alias
|
||||
} else {
|
||||
return this.user.firstName.substring(0, 1)
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
@ -38,22 +41,21 @@ export class PublishNameLogic {
|
||||
* first initial from user.lastName for PUBLISH_NAME_FIRST_INITIAL, PUBLISH_NAME_INITIALS
|
||||
*/
|
||||
public getLastName(publishNameType: PublishNameType): string {
|
||||
if (
|
||||
[
|
||||
PublishNameType.PUBLISH_NAME_LAST,
|
||||
PublishNameType.PUBLISH_NAME_INITIAL_LAST,
|
||||
PublishNameType.PUBLISH_NAME_FULL,
|
||||
].includes(publishNameType)
|
||||
) {
|
||||
if (PublishNameType.PUBLISH_NAME_FULL === publishNameType) {
|
||||
return this.user.lastName
|
||||
}
|
||||
if (
|
||||
} else if (
|
||||
[PublishNameType.PUBLISH_NAME_FIRST_INITIAL, PublishNameType.PUBLISH_NAME_INITIALS].includes(
|
||||
publishNameType,
|
||||
)
|
||||
) {
|
||||
return this.user.lastName.substring(0, 1)
|
||||
} else if (
|
||||
PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS === publishNameType &&
|
||||
!this.user.alias
|
||||
) {
|
||||
return this.user.lastName.substring(0, 1)
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ import { IsBoolean, IsEnum, IsInt, IsString } from 'class-validator'
|
||||
import { ArgsType, Field, InputType, Int } from 'type-graphql'
|
||||
|
||||
import { GmsPublishLocationType } from '@enum/GmsPublishLocationType'
|
||||
import { GmsPublishNameType } from '@enum/GmsPublishNameType'
|
||||
import { PublishNameType } from '@enum/PublishNameType'
|
||||
import { Location } from '@model/Location'
|
||||
|
||||
@ -55,9 +54,9 @@ export class UpdateUserInfosArgs {
|
||||
@IsBoolean()
|
||||
gmsAllowed?: boolean
|
||||
|
||||
@Field(() => GmsPublishNameType, { nullable: true })
|
||||
@IsEnum(GmsPublishNameType)
|
||||
gmsPublishName?: GmsPublishNameType | null
|
||||
@Field(() => PublishNameType, { nullable: true })
|
||||
@IsEnum(PublishNameType)
|
||||
gmsPublishName?: PublishNameType | null
|
||||
|
||||
@Field(() => PublishNameType, { nullable: true })
|
||||
@IsEnum(PublishNameType)
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
import { registerEnumType } from 'type-graphql'
|
||||
|
||||
export enum GmsPublishNameType {
|
||||
GMS_PUBLISH_NAME_ALIAS_OR_INITALS = 0,
|
||||
GMS_PUBLISH_NAME_INITIALS = 1,
|
||||
GMS_PUBLISH_NAME_FIRST = 2,
|
||||
GMS_PUBLISH_NAME_FIRST_INITIAL = 3,
|
||||
GMS_PUBLISH_NAME_FULL = 4,
|
||||
}
|
||||
|
||||
registerEnumType(GmsPublishNameType, {
|
||||
name: 'GmsPublishNameType', // this one is mandatory
|
||||
description: 'Type of name publishing', // this one is optional
|
||||
})
|
||||
@ -1,19 +1,14 @@
|
||||
import { registerEnumType } from 'type-graphql'
|
||||
|
||||
/**
|
||||
* Enum for decide which parts from first- and last-name are allowed to be published in an extern service
|
||||
*/
|
||||
export enum PublishNameType {
|
||||
PUBLISH_NAME_NONE = 0,
|
||||
PUBLISH_NAME_ALIAS_OR_INITALS = 0,
|
||||
PUBLISH_NAME_INITIALS = 1,
|
||||
PUBLISH_NAME_FIRST = 2,
|
||||
PUBLISH_NAME_FIRST_INITIAL = 3,
|
||||
PUBLISH_NAME_LAST = 4,
|
||||
PUBLISH_NAME_INITIAL_LAST = 5,
|
||||
PUBLISH_NAME_FULL = 6,
|
||||
PUBLISH_NAME_FULL = 4,
|
||||
}
|
||||
|
||||
registerEnumType(PublishNameType, {
|
||||
name: 'PublishNameType', // this one is mandatory
|
||||
description: 'Type of first- and last-name publishing for extern service', // this one is optional
|
||||
description: 'Type of name publishing', // this one is optional
|
||||
})
|
||||
|
||||
@ -2,7 +2,6 @@ import { User as dbUser } from '@entity/User'
|
||||
import { ObjectType, Field, Int } from 'type-graphql'
|
||||
|
||||
import { GmsPublishLocationType } from '@enum/GmsPublishLocationType'
|
||||
import { GmsPublishNameType } from '@enum/GmsPublishNameType'
|
||||
import { PublishNameType } from '@enum/PublishNameType'
|
||||
|
||||
import { KlickTipp } from './KlickTipp'
|
||||
@ -89,8 +88,8 @@ export class User {
|
||||
@Field(() => Boolean)
|
||||
gmsAllowed: boolean
|
||||
|
||||
@Field(() => GmsPublishNameType, { nullable: true })
|
||||
gmsPublishName: GmsPublishNameType | null
|
||||
@Field(() => PublishNameType, { nullable: true })
|
||||
gmsPublishName: PublishNameType | null
|
||||
|
||||
@Field(() => PublishNameType, { nullable: true })
|
||||
humhubPublishName: PublishNameType | null
|
||||
|
||||
@ -17,7 +17,6 @@ import { GraphQLError } from 'graphql'
|
||||
import { v4 as uuidv4, validate as validateUUID, version as versionUUID } from 'uuid'
|
||||
|
||||
import { GmsPublishLocationType } from '@enum/GmsPublishLocationType'
|
||||
import { GmsPublishNameType } from '@enum/GmsPublishNameType'
|
||||
import { OptInType } from '@enum/OptInType'
|
||||
import { PasswordEncryptionType } from '@enum/PasswordEncryptionType'
|
||||
import { RoleNames } from '@enum/RoleNames'
|
||||
@ -35,6 +34,7 @@ import {
|
||||
sendResetPasswordEmail,
|
||||
} from '@/emails/sendEmailVariants'
|
||||
import { EventType } from '@/event/Events'
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
import { SecretKeyCryptographyCreateKey } from '@/password/EncryptorUtils'
|
||||
import { encryptPassword } from '@/password/PasswordEncryptor'
|
||||
import { writeHomeCommunityEntry } from '@/seeds/community'
|
||||
@ -73,6 +73,8 @@ import { objectValuesToArray } from '@/util/utilities'
|
||||
|
||||
import { Location2Point } from './util/Location2Point'
|
||||
|
||||
jest.mock('@/apis/humhub/HumHubClient')
|
||||
|
||||
jest.mock('@/emails/sendEmailVariants', () => {
|
||||
const originalModule = jest.requireActual('@/emails/sendEmailVariants')
|
||||
return {
|
||||
@ -1232,7 +1234,7 @@ describe('UserResolver', () => {
|
||||
lastName: 'Blümchen',
|
||||
language: 'en',
|
||||
gmsAllowed: true,
|
||||
gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS,
|
||||
gmsPublishName: PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS,
|
||||
gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM,
|
||||
}),
|
||||
])
|
||||
@ -1272,7 +1274,7 @@ describe('UserResolver', () => {
|
||||
expect.objectContaining({
|
||||
alias: 'bibi_Bloxberg',
|
||||
gmsAllowed: true,
|
||||
gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS,
|
||||
gmsPublishName: PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS,
|
||||
gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM,
|
||||
}),
|
||||
])
|
||||
@ -1294,7 +1296,7 @@ describe('UserResolver', () => {
|
||||
await expect(User.find()).resolves.toEqual([
|
||||
expect.objectContaining({
|
||||
gmsAllowed: true,
|
||||
gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS,
|
||||
gmsPublishName: PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS,
|
||||
gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM,
|
||||
}),
|
||||
])
|
||||
@ -1307,8 +1309,7 @@ describe('UserResolver', () => {
|
||||
mutation: updateUserInfos,
|
||||
variables: {
|
||||
gmsAllowed: false,
|
||||
gmsPublishName:
|
||||
GmsPublishNameType[GmsPublishNameType.GMS_PUBLISH_NAME_FIRST_INITIAL],
|
||||
gmsPublishName: PublishNameType[PublishNameType.PUBLISH_NAME_FIRST_INITIAL],
|
||||
gmsPublishLocation:
|
||||
GmsPublishLocationType[GmsPublishLocationType.GMS_LOCATION_TYPE_APPROXIMATE],
|
||||
},
|
||||
@ -1316,7 +1317,7 @@ describe('UserResolver', () => {
|
||||
await expect(User.find()).resolves.toEqual([
|
||||
expect.objectContaining({
|
||||
gmsAllowed: false,
|
||||
gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_FIRST_INITIAL,
|
||||
gmsPublishName: PublishNameType.PUBLISH_NAME_FIRST_INITIAL,
|
||||
gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_APPROXIMATE,
|
||||
}),
|
||||
])
|
||||
@ -1332,8 +1333,7 @@ describe('UserResolver', () => {
|
||||
mutation: updateUserInfos,
|
||||
variables: {
|
||||
gmsAllowed: true,
|
||||
gmsPublishName:
|
||||
GmsPublishNameType[GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS],
|
||||
gmsPublishName: PublishNameType[PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS],
|
||||
gmsLocation: loc,
|
||||
gmsPublishLocation:
|
||||
GmsPublishLocationType[GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM],
|
||||
@ -1342,7 +1342,7 @@ describe('UserResolver', () => {
|
||||
await expect(User.find()).resolves.toEqual([
|
||||
expect.objectContaining({
|
||||
gmsAllowed: true,
|
||||
gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS,
|
||||
gmsPublishName: PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS,
|
||||
location: Location2Point(loc),
|
||||
gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM,
|
||||
}),
|
||||
|
||||
@ -10,6 +10,7 @@ import { UserContact as DbUserContact } from '@entity/UserContact'
|
||||
import { UserRole } from '@entity/UserRole'
|
||||
import i18n from 'i18n'
|
||||
import { Resolver, Query, Args, Arg, Authorized, Ctx, Mutation, Int } from 'type-graphql'
|
||||
import { IRestResponse } from 'typed-rest-client'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { UserArgs } from '@arg//UserArgs'
|
||||
@ -31,6 +32,8 @@ import { UserAdmin, SearchUsersResult } from '@model/UserAdmin'
|
||||
|
||||
import { updateGmsUser } from '@/apis/gms/GmsClient'
|
||||
import { GmsUser } from '@/apis/gms/model/GmsUser'
|
||||
import { HumHubClient } from '@/apis/humhub/HumHubClient'
|
||||
import { GetUser } from '@/apis/humhub/model/GetUser'
|
||||
import { subscribe } from '@/apis/KlicktippController'
|
||||
import { encode } from '@/auth/JWT'
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
@ -157,11 +160,17 @@ export class UserResolver {
|
||||
// TODO we want to catch this on the frontend and ask the user to check his emails or resend code
|
||||
throw new LogError('The User has not set a password yet', dbUser)
|
||||
}
|
||||
|
||||
if (!verifyPassword(dbUser, password)) {
|
||||
throw new LogError('No user with this credentials', dbUser)
|
||||
}
|
||||
|
||||
// request to humhub and klicktipp run in parallel
|
||||
let humhubUserPromise: Promise<IRestResponse<GetUser>> | undefined
|
||||
const klicktippStatePromise = getKlicktippState(dbUser.emailContact.email)
|
||||
if (CONFIG.HUMHUB_ACTIVE && dbUser.humhubAllowed) {
|
||||
humhubUserPromise = HumHubClient.getInstance()?.userByUsernameAsync(email)
|
||||
}
|
||||
|
||||
if (dbUser.passwordEncryptionType !== PasswordEncryptionType.GRADIDO_ID) {
|
||||
dbUser.passwordEncryptionType = PasswordEncryptionType.GRADIDO_ID
|
||||
dbUser.password = encryptPassword(dbUser, password)
|
||||
@ -183,7 +192,6 @@ export class UserResolver {
|
||||
dbUser.publisherId = publisherId
|
||||
await DbUser.save(dbUser)
|
||||
}
|
||||
user.klickTipp = await getKlicktippState(dbUser.emailContact.email)
|
||||
|
||||
context.setHeaders.push({
|
||||
key: 'token',
|
||||
@ -191,6 +199,12 @@ export class UserResolver {
|
||||
})
|
||||
|
||||
await EVENT_USER_LOGIN(dbUser)
|
||||
// load humhub state
|
||||
if (humhubUserPromise) {
|
||||
const result = await humhubUserPromise
|
||||
user.humhubAllowed = result?.result?.account.status === 1
|
||||
}
|
||||
user.klickTipp = await klicktippStatePromise
|
||||
logger.info(`successful Login: ${JSON.stringify(user, null, 2)}`)
|
||||
return user
|
||||
}
|
||||
@ -703,6 +717,26 @@ export class UserResolver {
|
||||
return result
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.HUMHUB_AUTO_LOGIN])
|
||||
@Query(() => String)
|
||||
async authenticateHumhubAutoLogin(@Ctx() context: Context): Promise<string> {
|
||||
logger.info(`authenticateHumhubAutoLogin()...`)
|
||||
const dbUser = getUser(context)
|
||||
const humhubClient = HumHubClient.getInstance()
|
||||
if (!humhubClient) {
|
||||
throw new LogError('cannot create humhub client')
|
||||
}
|
||||
const username = dbUser.alias ?? dbUser.gradidoID
|
||||
const humhubUser = await humhubClient.userByUsername(username)
|
||||
if (!humhubUser) {
|
||||
throw new LogError("user don't exist (any longer) on humhub")
|
||||
}
|
||||
if (humhubUser.account.status !== 1) {
|
||||
throw new LogError('user status is not 1', humhubUser.account.status)
|
||||
}
|
||||
return await humhubClient.createAutoLoginUrl(username)
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.SEARCH_ADMIN_USERS])
|
||||
@Query(() => SearchAdminUsersResult)
|
||||
async searchAdminUsers(
|
||||
|
||||
@ -2,7 +2,7 @@ import { Point } from '@dbTools/typeorm'
|
||||
import { User as DbUser } from '@entity/User'
|
||||
|
||||
import { UpdateUserInfosArgs } from '@/graphql/arg/UpdateUserInfosArgs'
|
||||
import { GmsPublishNameType } from '@/graphql/enum/GmsPublishNameType'
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
|
||||
@ -22,11 +22,10 @@ export function compareGmsRelevantUserSettings(
|
||||
orgUser.alias !== updateUserInfosArgs.alias &&
|
||||
((updateUserInfosArgs.gmsPublishName &&
|
||||
updateUserInfosArgs.gmsPublishName.valueOf ===
|
||||
GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS.valueOf) ||
|
||||
PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS.valueOf) ||
|
||||
(!updateUserInfosArgs.gmsPublishName &&
|
||||
orgUser.gmsPublishName &&
|
||||
orgUser.gmsPublishName.valueOf ===
|
||||
GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS.valueOf))
|
||||
orgUser.gmsPublishName.valueOf === PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS.valueOf))
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ import { UserContact } from '@entity/UserContact'
|
||||
|
||||
import { HumHubClient } from '@/apis/humhub/HumHubClient'
|
||||
import { GetUser } from '@/apis/humhub/model/GetUser'
|
||||
import { ExecutedHumhubAction } from '@/apis/humhub/syncUser'
|
||||
import { UpdateUserInfosArgs } from '@/graphql/arg/UpdateUserInfosArgs'
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
@ -22,19 +21,12 @@ const mockUpdateUserInfosArg = new UpdateUserInfosArgs()
|
||||
const mockHumHubUser = new GetUser(mockUser, 1)
|
||||
|
||||
describe('syncHumhub', () => {
|
||||
beforeAll(() => {
|
||||
// humhubClientMockbBeforeAll()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(logger, 'debug').mockImplementation()
|
||||
jest.spyOn(logger, 'info').mockImplementation()
|
||||
jest.spyOn(HumHubClient, 'getInstance')
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
// humhubClientMockbAfterEach()
|
||||
})
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
@ -43,7 +35,7 @@ describe('syncHumhub', () => {
|
||||
await syncHumhub(mockUpdateUserInfosArg, new User())
|
||||
expect(HumHubClient.getInstance).not.toBeCalled()
|
||||
// language logging from some other place
|
||||
expect(logger.debug).toBeCalledTimes(4)
|
||||
expect(logger.debug).toBeCalledTimes(5)
|
||||
expect(logger.info).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
@ -51,11 +43,11 @@ describe('syncHumhub', () => {
|
||||
mockUpdateUserInfosArg.firstName = 'New' // Relevant changes
|
||||
mockUser.firstName = 'New'
|
||||
await syncHumhub(mockUpdateUserInfosArg, mockUser)
|
||||
expect(logger.debug).toHaveBeenCalledTimes(7) // Four language logging calls, two debug calls in function, one for not syncing
|
||||
expect(logger.debug).toHaveBeenCalledTimes(8) // Four language logging calls, two debug calls in function, one for not syncing
|
||||
expect(logger.info).toHaveBeenLastCalledWith('finished sync user with humhub', {
|
||||
localId: mockUser.id,
|
||||
externId: mockHumHubUser.id,
|
||||
result: ExecutedHumhubAction.UPDATE,
|
||||
result: 'UPDATE',
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import { User } from '@entity/User'
|
||||
|
||||
import { HumHubClient } from '@/apis/humhub/HumHubClient'
|
||||
import { GetUser } from '@/apis/humhub/model/GetUser'
|
||||
import { syncUser } from '@/apis/humhub/syncUser'
|
||||
import { ExecutedHumhubAction, syncUser } from '@/apis/humhub/syncUser'
|
||||
import { UpdateUserInfosArgs } from '@/graphql/arg/UpdateUserInfosArgs'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
|
||||
@ -12,13 +12,14 @@ export async function syncHumhub(
|
||||
): Promise<void> {
|
||||
// check for humhub relevant changes
|
||||
if (
|
||||
!updateUserInfosArg.alias &&
|
||||
!updateUserInfosArg.firstName &&
|
||||
!updateUserInfosArg.lastName &&
|
||||
!updateUserInfosArg.humhubAllowed &&
|
||||
!updateUserInfosArg.humhubPublishName &&
|
||||
!updateUserInfosArg.language
|
||||
updateUserInfosArg.alias === undefined &&
|
||||
updateUserInfosArg.firstName === undefined &&
|
||||
updateUserInfosArg.lastName === undefined &&
|
||||
updateUserInfosArg.humhubAllowed === undefined &&
|
||||
updateUserInfosArg.humhubPublishName === undefined &&
|
||||
updateUserInfosArg.language === undefined
|
||||
) {
|
||||
logger.debug('no relevant changes')
|
||||
return
|
||||
}
|
||||
logger.debug('changed user-settings relevant for humhub-user update...')
|
||||
@ -27,7 +28,7 @@ export async function syncHumhub(
|
||||
return
|
||||
}
|
||||
logger.debug('retrieve user from humhub')
|
||||
const humhubUser = await humhubClient.userByEmail(user.emailContact.email)
|
||||
const humhubUser = await humhubClient.userByUsername(user.alias ?? user.gradidoID)
|
||||
const humhubUsers = new Map<string, GetUser>()
|
||||
if (humhubUser) {
|
||||
humhubUsers.set(user.emailContact.email, humhubUser)
|
||||
@ -37,6 +38,9 @@ export async function syncHumhub(
|
||||
logger.info('finished sync user with humhub', {
|
||||
localId: user.id,
|
||||
externId: humhubUser?.id,
|
||||
result,
|
||||
// for preventing this warning https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/rules/detect-object-injection.md
|
||||
// and possible danger coming with it
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
result: ExecutedHumhubAction[result as ExecutedHumhubAction],
|
||||
})
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ export const updateUserInfos = gql`
|
||||
$hideAmountGDD: Boolean
|
||||
$hideAmountGDT: Boolean
|
||||
$gmsAllowed: Boolean
|
||||
$gmsPublishName: GmsPublishNameType
|
||||
$gmsPublishName: PublishNameType
|
||||
$gmsLocation: Location
|
||||
$gmsPublishLocation: GmsPublishLocationType
|
||||
) {
|
||||
|
||||
@ -25,7 +25,7 @@ EMAIL_CODE_REQUEST_TIME=10
|
||||
# Need to adjust by updates
|
||||
# config versions
|
||||
DATABASE_CONFIG_VERSION=v1.2022-03-18
|
||||
BACKEND_CONFIG_VERSION=v21.2024-01-06
|
||||
BACKEND_CONFIG_VERSION=v23.2024-04-04
|
||||
FRONTEND_CONFIG_VERSION=v6.2024-02-27
|
||||
ADMIN_CONFIG_VERSION=v2.2024-01-04
|
||||
FEDERATION_CONFIG_VERSION=v2.2023-08-24
|
||||
|
||||
@ -4,7 +4,7 @@ module.exports = {
|
||||
collectCoverageFrom: ['src/**/*.{js,vue}', '!**/node_modules/**', '!**/?(*.)+(spec|test).js?(x)'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
lines: 94,
|
||||
lines: 93,
|
||||
},
|
||||
},
|
||||
moduleFileExtensions: [
|
||||
|
||||
7
frontend/public/img/svg/circles.svg
Normal file
7
frontend/public/img/svg/circles.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200" height="200">
|
||||
<!-- Personen in Kreisen -->
|
||||
<circle cx="30" cy="50" r="15" fill="none" stroke="black" stroke-width="2"/>
|
||||
<circle cx="50" cy="30" r="15" fill="none" stroke="black" stroke-width="2"/>
|
||||
<circle cx="70" cy="50" r="15" fill="none" stroke="black" stroke-width="2"/>
|
||||
<circle cx="50" cy="70" r="15" fill="none" stroke="black" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 442 B |
@ -35,9 +35,9 @@ describe('Sidebar', () => {
|
||||
expect(wrapper.find('div#component-sidebar').exists()).toBe(true)
|
||||
})
|
||||
|
||||
describe('the genaral section', () => {
|
||||
it('has six nav-items', () => {
|
||||
expect(wrapper.findAll('ul').at(0).findAll('.nav-item')).toHaveLength(6)
|
||||
describe('the general section', () => {
|
||||
it('has seven nav-items', () => {
|
||||
expect(wrapper.findAll('ul').at(0).findAll('.nav-item')).toHaveLength(7)
|
||||
})
|
||||
|
||||
it('has nav-item "navigation.overview" in navbar', () => {
|
||||
@ -60,8 +60,12 @@ describe('Sidebar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(4).text()).toContain('navigation.info')
|
||||
})
|
||||
|
||||
it('has nav-item "usersearch" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(5).text()).toContain('navigation.usersearch')
|
||||
it('has nav-item "navigation.circles" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(5).text()).toContain('navigation.circles')
|
||||
})
|
||||
|
||||
it('has nav-item "navigation.usersearch" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(6).text()).toContain('navigation.usersearch')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -28,6 +28,10 @@
|
||||
<b-img src="/img/svg/info.svg" height="20" class="svg-icon" />
|
||||
<span class="ml-2">{{ $t('navigation.info') }}</span>
|
||||
</b-nav-item>
|
||||
<b-nav-item to="/circles" class="mb-3" active-class="activeRoute">
|
||||
<b-img src="/img/svg/circles.svg" height="20" class="svg-icon" />
|
||||
<span class="ml-2">{{ $t('navigation.circles') }}</span>
|
||||
</b-nav-item>
|
||||
<b-nav-item to="/usersearch" active-class="activeRoute">
|
||||
<b-img src="/img/loupe.png" height="20" />
|
||||
<span class="ml-2">{{ $t('navigation.usersearch') }}</span>
|
||||
|
||||
@ -1,84 +0,0 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import UserGMSNamingFormat from './UserGMSNamingFormat.vue'
|
||||
import { toastErrorSpy } from '@test/testSetup'
|
||||
|
||||
const mockAPIcall = jest.fn()
|
||||
|
||||
const storeCommitMock = jest.fn()
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
describe('UserNamingFormat', () => {
|
||||
let wrapper
|
||||
beforeEach(() => {
|
||||
wrapper = mount(UserGMSNamingFormat, {
|
||||
mocks: {
|
||||
$t: (key) => key, // Mocking the translation function
|
||||
$store: {
|
||||
state: {
|
||||
gmsPublishName: null,
|
||||
},
|
||||
commit: storeCommitMock,
|
||||
},
|
||||
$apollo: {
|
||||
mutate: mockAPIcall,
|
||||
},
|
||||
},
|
||||
localVue,
|
||||
propsData: {
|
||||
selectedOption: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS',
|
||||
initialValue: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS',
|
||||
attrName: 'gmsPublishName',
|
||||
successMessage: 'success message',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy()
|
||||
})
|
||||
|
||||
it('renders the correct dropdown options', () => {
|
||||
const dropdownItems = wrapper.findAll('.dropdown-item')
|
||||
expect(dropdownItems.length).toBe(5)
|
||||
|
||||
const labels = dropdownItems.wrappers.map((item) => item.text())
|
||||
expect(labels).toEqual([
|
||||
'settings.GMS.publish-name.alias-or-initials',
|
||||
'settings.GMS.publish-name.initials',
|
||||
'settings.GMS.publish-name.first',
|
||||
'settings.GMS.publish-name.first-initial',
|
||||
'settings.GMS.publish-name.name-full',
|
||||
])
|
||||
})
|
||||
|
||||
it('updates selected option on click', async () => {
|
||||
const dropdownItem = wrapper.findAll('.dropdown-item').at(3) // Click the fourth item
|
||||
await dropdownItem.trigger('click')
|
||||
|
||||
expect(wrapper.emitted().valueChanged).toBeTruthy()
|
||||
expect(wrapper.emitted().valueChanged.length).toBe(1)
|
||||
expect(wrapper.emitted().valueChanged[0]).toEqual(['GMS_PUBLISH_NAME_FIRST_INITIAL'])
|
||||
})
|
||||
|
||||
it('does not update when clicking on already selected option', async () => {
|
||||
const dropdownItem = wrapper.findAll('.dropdown-item').at(0) // Click the first item (which is already selected)
|
||||
await dropdownItem.trigger('click')
|
||||
|
||||
expect(wrapper.emitted().valueChanged).toBeFalsy()
|
||||
})
|
||||
|
||||
describe('update with error', () => {
|
||||
beforeEach(async () => {
|
||||
mockAPIcall.mockRejectedValue({
|
||||
message: 'Ouch',
|
||||
})
|
||||
const dropdownItem = wrapper.findAll('.dropdown-item').at(2) // Click the third item
|
||||
await dropdownItem.trigger('click')
|
||||
})
|
||||
|
||||
it('toasts an error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('Ouch')
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,92 +0,0 @@
|
||||
<template>
|
||||
<div class="user-g-m-s-naming-format">
|
||||
<b-dropdown v-model="selectedOption">
|
||||
<template slot="button-content">{{ selectedOptionLabel }}</template>
|
||||
<b-dropdown-item
|
||||
v-for="option in dropdownOptions"
|
||||
@click.prevent="update(option)"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
:title="option.title"
|
||||
>
|
||||
{{ option.label }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { updateUserInfos } from '@/graphql/mutations'
|
||||
|
||||
export default {
|
||||
name: 'UserGMSNamingFormat',
|
||||
props: {
|
||||
initialValue: { type: String, default: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS' },
|
||||
attrName: { type: String },
|
||||
successMessage: { type: String },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedOption: this.initialValue,
|
||||
dropdownOptions: [
|
||||
{
|
||||
label: this.$t('settings.GMS.publish-name.alias-or-initials'),
|
||||
title: this.$t('settings.GMS.publish-name.alias-or-initials-tooltip'),
|
||||
value: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS',
|
||||
},
|
||||
{
|
||||
label: this.$t('settings.GMS.publish-name.initials'),
|
||||
title: this.$t('settings.GMS.publish-name.initials-tooltip'),
|
||||
value: 'GMS_PUBLISH_NAME_INITIALS',
|
||||
},
|
||||
{
|
||||
label: this.$t('settings.GMS.publish-name.first'),
|
||||
title: this.$t('settings.GMS.publish-name.first-tooltip'),
|
||||
value: 'GMS_PUBLISH_NAME_FIRST',
|
||||
},
|
||||
{
|
||||
label: this.$t('settings.GMS.publish-name.first-initial'),
|
||||
title: this.$t('settings.GMS.publish-name.first-initial-tooltip'),
|
||||
value: 'GMS_PUBLISH_NAME_FIRST_INITIAL',
|
||||
},
|
||||
{
|
||||
label: this.$t('settings.GMS.publish-name.name-full'),
|
||||
title: this.$t('settings.GMS.publish-name.name-full-tooltip'),
|
||||
value: 'GMS_PUBLISH_NAME_FULL',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedOptionLabel() {
|
||||
return this.dropdownOptions.find((option) => option.value === this.selectedOption).label
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async update(option) {
|
||||
if (option.value === this.selectedOption) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const variables = []
|
||||
variables[this.attrName] = option.value
|
||||
await this.$apollo.mutate({
|
||||
mutation: updateUserInfos,
|
||||
variables,
|
||||
})
|
||||
this.toastSuccess(this.successMessage)
|
||||
this.selectedOption = option.value
|
||||
this.$store.commit(this.attrName, option.value)
|
||||
this.$emit('valueChanged', option.value)
|
||||
} catch (error) {
|
||||
this.toastError(error.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.user-g-m-s-naming-format > .dropdown,
|
||||
.user-g-m-s-naming-format > .dropdown > .dropdown-toggle > ul.dropdown-menu {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -26,9 +26,9 @@ describe('UserNamingFormat', () => {
|
||||
},
|
||||
localVue,
|
||||
propsData: {
|
||||
selectedOption: 'PUBLISH_NAME_NONE',
|
||||
initialValue: 'PUBLISH_NAME_NONE',
|
||||
attrName: 'publishName',
|
||||
selectedOption: 'PUBLISH_NAME_ALIAS_OR_INITALS',
|
||||
initialValue: 'PUBLISH_NAME_ALIAS_OR_INITALS',
|
||||
attrName: 'gmsPublishName',
|
||||
successMessage: 'success message',
|
||||
},
|
||||
})
|
||||
@ -40,17 +40,15 @@ describe('UserNamingFormat', () => {
|
||||
|
||||
it('renders the correct dropdown options', () => {
|
||||
const dropdownItems = wrapper.findAll('.dropdown-item')
|
||||
expect(dropdownItems.length).toBe(7)
|
||||
expect(dropdownItems.length).toBe(5)
|
||||
|
||||
const labels = dropdownItems.wrappers.map((item) => item.text())
|
||||
expect(labels).toEqual([
|
||||
'settings.publish-name.none',
|
||||
'settings.publish-name.alias-or-initials',
|
||||
'settings.publish-name.initials',
|
||||
'settings.publish-name.first',
|
||||
'settings.publish-name.first-initial',
|
||||
'settings.publish-name.last',
|
||||
'settings.publish-name.last-initial',
|
||||
'settings.publish-name.full',
|
||||
'settings.publish-name.name-full',
|
||||
])
|
||||
})
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ import { updateUserInfos } from '@/graphql/mutations'
|
||||
export default {
|
||||
name: 'UserNamingFormat',
|
||||
props: {
|
||||
initialValue: { type: String, default: 'PUBLISH_NAME_NONE' },
|
||||
initialValue: { type: String, default: 'PUBLISH_NAME_ALIAS_OR_INITALS' },
|
||||
attrName: { type: String },
|
||||
successMessage: { type: String },
|
||||
},
|
||||
@ -29,9 +29,9 @@ export default {
|
||||
selectedOption: this.initialValue,
|
||||
dropdownOptions: [
|
||||
{
|
||||
label: this.$t('settings.publish-name.none'),
|
||||
title: this.$t('settings.publish-name.none-tooltip'),
|
||||
value: 'PUBLISH_NAME_NONE',
|
||||
label: this.$t('settings.publish-name.alias-or-initials'),
|
||||
title: this.$t('settings.publish-name.alias-or-initials-tooltip'),
|
||||
value: 'PUBLISH_NAME_ALIAS_OR_INITALS',
|
||||
},
|
||||
{
|
||||
label: this.$t('settings.publish-name.initials'),
|
||||
@ -49,18 +49,8 @@ export default {
|
||||
value: 'PUBLISH_NAME_FIRST_INITIAL',
|
||||
},
|
||||
{
|
||||
label: this.$t('settings.publish-name.last'),
|
||||
title: this.$t('settings.publish-name.last-tooltip'),
|
||||
value: 'PUBLISH_NAME_LAST',
|
||||
},
|
||||
{
|
||||
label: this.$t('settings.publish-name.last-initial'),
|
||||
title: this.$t('settings.publish-name.last-initial-tooltip'),
|
||||
value: 'PUBLISH_NAME_INITIAL_LAST',
|
||||
},
|
||||
{
|
||||
label: this.$t('settings.publish-name.full'),
|
||||
title: this.$t('settings.publish-name.full-tooltip'),
|
||||
label: this.$t('settings.publish-name.name-full'),
|
||||
title: this.$t('settings.publish-name.name-full-tooltip'),
|
||||
value: 'PUBLISH_NAME_FULL',
|
||||
},
|
||||
],
|
||||
@ -68,7 +58,10 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
selectedOptionLabel() {
|
||||
return this.dropdownOptions.find((option) => option.value === this.selectedOption).label
|
||||
const selected = this.dropdownOptions.find((option) => option.value === this.selectedOption)
|
||||
.label
|
||||
return selected || this.$t('settings.publish-name.alias-or-initials')
|
||||
// return this.dropdownOptions.find((option) => option.value === this.selectedOption).label
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<div class="form-user-switch">
|
||||
<div class="form-user-switch" @click="onClick">
|
||||
<b-form-checkbox
|
||||
test="BFormCheckbox"
|
||||
v-model="value"
|
||||
name="check-button"
|
||||
:disabled="disabled"
|
||||
switch
|
||||
@change="onChange"
|
||||
></b-form-checkbox>
|
||||
@ -19,6 +20,8 @@ export default {
|
||||
attrName: { type: String },
|
||||
enabledText: { type: String },
|
||||
disabledText: { type: String },
|
||||
disabled: { type: Boolean, default: false },
|
||||
notAllowedText: { type: String, default: undefined },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -27,9 +30,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async onChange() {
|
||||
if (this.isDisabled) return
|
||||
const variables = []
|
||||
variables[this.attrName] = this.value
|
||||
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: updateUserInfos,
|
||||
@ -45,6 +48,11 @@ export default {
|
||||
this.toastError(error.message)
|
||||
})
|
||||
},
|
||||
onClick() {
|
||||
if (this.notAllowedText && this.disabled) {
|
||||
this.toastError(this.notAllowedText)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -36,7 +36,7 @@ export const updateUserInfos = gql`
|
||||
$hideAmountGDT: Boolean
|
||||
$gmsAllowed: Boolean
|
||||
$humhubAllowed: Boolean
|
||||
$gmsPublishName: GmsPublishNameType
|
||||
$gmsPublishName: PublishNameType
|
||||
$humhubPublishName: PublishNameType
|
||||
$gmsLocation: Location
|
||||
$gmsPublishLocation: GmsPublishLocationType
|
||||
|
||||
@ -28,6 +28,12 @@ export const authenticateGmsUserSearch = gql`
|
||||
}
|
||||
`
|
||||
|
||||
export const authenticateHumhubAutoLogin = gql`
|
||||
query {
|
||||
authenticateHumhubAutoLogin
|
||||
}
|
||||
`
|
||||
|
||||
export const transactionsQuery = gql`
|
||||
query($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) {
|
||||
transactionList(currentPage: $currentPage, pageSize: $pageSize, order: $order) {
|
||||
|
||||
@ -5,11 +5,16 @@
|
||||
"1000thanks": "1000 Dank, weil du bei uns bist!",
|
||||
"125": "125%",
|
||||
"85": "85%",
|
||||
"ExternServices": "Verknüpfte Dienste",
|
||||
"GDD": "GDD",
|
||||
"GDT": "GDT",
|
||||
"GMS": "Gradido Karte",
|
||||
"Humhub": "Gradido Community",
|
||||
"GMS": {
|
||||
"title": "Geo Matching System GMS (in Entwicklung)",
|
||||
"desc": "Finde Mitglieder aller Communities auf einer Landkarte."
|
||||
},
|
||||
"Humhub": {
|
||||
"title": "Gradido-Kreise",
|
||||
"desc": "Gemeinsam unterstützen wir einander – achtsam in Kreiskultur."
|
||||
},
|
||||
"PersonalDetails": "Persönliche Angaben",
|
||||
"advanced-calculation": "Vorausberechnung",
|
||||
"asterisks": "****",
|
||||
@ -25,6 +30,11 @@
|
||||
}
|
||||
},
|
||||
"back": "Zurück",
|
||||
"circles": {
|
||||
"headline": "Gemeinsam unterstützen wir einander – achtsam in Kreiskultur.",
|
||||
"text": "In geschützten Räumen können wir frei kommunizieren und kooperieren, ohne auf die sozialen Medien angewiesen zu sein. Mit Klick auf den Button öffnest Du die Kooperationsplattform in einem neuen Browser-Fenster.",
|
||||
"button": "Gradido-Kreise starten..."
|
||||
},
|
||||
"community": {
|
||||
"admins": "Administratoren",
|
||||
"choose-another-community": "Eine andere Gemeinschaft auswählen",
|
||||
@ -268,6 +278,7 @@
|
||||
"overview": "Übersicht",
|
||||
"send": "Senden",
|
||||
"settings": "Einstellung",
|
||||
"circles": "Kreise",
|
||||
"support": "Support",
|
||||
"transactions": "Transaktionen",
|
||||
"usersearch": "Nutzersuche"
|
||||
@ -280,6 +291,7 @@
|
||||
"overview": "Willkommen {name}",
|
||||
"send": "Sende Gradidos",
|
||||
"settings": "Einstellungen",
|
||||
"circles": "Gradido Kreise (Beta)",
|
||||
"transactions": "Deine Transaktionen",
|
||||
"usersearch": "Geografische Nutzersuche"
|
||||
},
|
||||
@ -294,6 +306,8 @@
|
||||
"warningText": "Bist du noch da?"
|
||||
},
|
||||
"settings": {
|
||||
"allow-community-services": "Community-Dienste erlauben",
|
||||
"community": "Community",
|
||||
"emailInfo": "Kann aktuell noch nicht geändert werden.",
|
||||
"GMS": {
|
||||
"disabled": "Daten werden nicht nach GMS exportiert",
|
||||
@ -302,8 +316,8 @@
|
||||
"label": "Positionsbestimmung",
|
||||
"button": "Klick mich!"
|
||||
},
|
||||
"location-format": "Positionstyp",
|
||||
"naming-format": "Namensformat im GMS",
|
||||
"location-format": "Position auf Karte anzeigen:",
|
||||
"naming-format": "Namen anzeigen:",
|
||||
"publish-location": {
|
||||
"exact": "Genaue Position",
|
||||
"approximate": "Ungefähre Position",
|
||||
@ -311,30 +325,19 @@
|
||||
"updated": "Positionstyp für GMS aktualisiert"
|
||||
},
|
||||
"publish-name": {
|
||||
"alias-or-initials": "Benutzername oder Initialen",
|
||||
"alias-or-initials-tooltip": "Benutzername, falls vorhanden, oder die Initialen von Vorname und Nachname",
|
||||
"first": "Vorname",
|
||||
"first-tooltip": "Nur der Vornamen",
|
||||
"first-initial": "Vorname und Initiale",
|
||||
"first-initial-tooltip": "Vornamen plus Anfangsbuchstabe des Nachnamens",
|
||||
"initials": "Initialen",
|
||||
"initials-tooltip": "Initialen von Vor- und Nachname unabhängig von der Existenz des Benutzernamens",
|
||||
"name-full": "Ganzer Name",
|
||||
"name-full-tooltip": "Vollständiger Name: Vorname plus Nachname",
|
||||
"updated": "Namensformat für GMS aktualisiert"
|
||||
},
|
||||
"switch": "Erlaubnis Daten nach GMS zu exportieren."
|
||||
}
|
||||
},
|
||||
"hideAmountGDD": "Dein GDD Betrag ist versteckt.",
|
||||
"hideAmountGDT": "Dein GDT Betrag ist versteckt.",
|
||||
"humhub": {
|
||||
"delete-disabled": "Das Benutzerkonto kann nur im Profil-Menü der Kooperationsplattform gelöscht werden.",
|
||||
"disabled": "Daten werden nicht in die Gradido Community exportiert",
|
||||
"enabled": "Daten werden in die Gradido Community exportiert",
|
||||
"naming-format": "Namensformat in der Gradido Community",
|
||||
"naming-format": "Namen anzeigen:",
|
||||
"publish-name": {
|
||||
"updated": "Namensformat für die Gradido Community aktualisiert."
|
||||
},
|
||||
"switch": "Erlaubnis Daten in die Gradido Community zu exportieren."
|
||||
}
|
||||
},
|
||||
"info": "Transaktionen können nun per Benutzername oder E-Mail-Adresse getätigt werden.",
|
||||
"language": {
|
||||
@ -374,20 +377,16 @@
|
||||
"subtitle": "Wenn du dein Passwort vergessen hast, kannst du es hier zurücksetzen."
|
||||
},
|
||||
"publish-name": {
|
||||
"none": "Keine",
|
||||
"none-tooltip": "Vorname und Nachname bleiben leer",
|
||||
"alias-or-initials": "Benutzername oder Initialen",
|
||||
"alias-or-initials-tooltip": "Benutzername, falls vorhanden, oder die Initialen von Vorname und Nachname",
|
||||
"first": "Vorname",
|
||||
"first-tooltip": "Nur der Vornamen, z.B. Max",
|
||||
"first-initial": "Vorname und Initiale",
|
||||
"first-initial-tooltip": "Vornamen plus Anfangsbuchstabe des Nachnamens, z.B. Max M.",
|
||||
"last": "Nachname",
|
||||
"last-tooltip": "Nur der Nachname, z.B. Mustermann",
|
||||
"last-initial": "Initiale und Nachname",
|
||||
"last-initial-tooltip": "Anfangsbuchstabe des Vornamen plus Nachname, z.B. M. Mustermann",
|
||||
"first-tooltip": "Nur der Vornamen",
|
||||
"first-initial": "Vorname und Initial",
|
||||
"first-initial-tooltip": "Vornamen plus Anfangsbuchstabe des Nachnamens",
|
||||
"initials": "Initialen",
|
||||
"initials-tooltip": "Nur die Initialen von Vor- und Nachname, z.B. M. M.",
|
||||
"full": "Ganzer Name",
|
||||
"full-tooltip": "Vollständiger Name: Vorname plus Nachname, z.B. Max Mustermann"
|
||||
"initials-tooltip": "Initialen von Vor- und Nachname unabhängig von der Existenz des Benutzernamens",
|
||||
"name-full": "Vorname und Nachname",
|
||||
"name-full-tooltip": "Vollständiger Name: Vorname plus Nachname"
|
||||
},
|
||||
"showAmountGDD": "Dein GDD Betrag ist sichtbar.",
|
||||
"showAmountGDT": "Dein GDT Betrag ist sichtbar.",
|
||||
|
||||
@ -5,11 +5,16 @@
|
||||
"1000thanks": "1000 thanks for being with us!",
|
||||
"125": "125%",
|
||||
"85": "85%",
|
||||
"ExternServices": "Extern Services",
|
||||
"GDD": "GDD",
|
||||
"GDT": "GDT",
|
||||
"GMS": "Gradido Map",
|
||||
"Humhub": "Gradido Community",
|
||||
"GMS": {
|
||||
"title": "Geo Matching System GMS (in develop)",
|
||||
"desc": "Find members of all communities on a map."
|
||||
},
|
||||
"Humhub": {
|
||||
"title": "Gradido-circles",
|
||||
"desc": "Together we support each other - mindful in circle culture."
|
||||
},
|
||||
"PersonalDetails": "Personal details",
|
||||
"advanced-calculation": "Advanced calculation",
|
||||
"asterisks": "****",
|
||||
@ -25,6 +30,11 @@
|
||||
}
|
||||
},
|
||||
"back": "Back",
|
||||
"circles": {
|
||||
"headline": "Together we support each other - mindful in circle culture.",
|
||||
"text": "We can communicate and collaborate freely in protected spaces without having to rely on social media. Click on the button to open the collaboration platform in a new browser window.",
|
||||
"button": "Gradido circles start..."
|
||||
},
|
||||
"community": {
|
||||
"admins": "Administrators",
|
||||
"choose-another-community": "Choose another community",
|
||||
@ -268,6 +278,7 @@
|
||||
"overview": "Overview",
|
||||
"send": "Send",
|
||||
"settings": "Settings",
|
||||
"circles": "Circle",
|
||||
"support": "Support",
|
||||
"transactions": "Transactions",
|
||||
"usersearch": "Geographical User Search"
|
||||
@ -281,6 +292,7 @@
|
||||
"send": "Send Gradidos",
|
||||
"settings": "Settings",
|
||||
"transactions": "Your transactions",
|
||||
"circles": "Gradido Circles (Beta)",
|
||||
"usersearch": "Geographical User Search"
|
||||
},
|
||||
"qrCode": "QR Code",
|
||||
@ -294,6 +306,8 @@
|
||||
"warningText": "Are you still there?"
|
||||
},
|
||||
"settings": {
|
||||
"allow-community-services": "Allow Community Services",
|
||||
"community": "Community",
|
||||
"emailInfo": "Cannot be changed at this time.",
|
||||
"GMS": {
|
||||
"disabled": "Data not exported to GMS",
|
||||
@ -302,8 +316,8 @@
|
||||
"label": "pinpoint location",
|
||||
"button": "click me!"
|
||||
},
|
||||
"location-format": "location type",
|
||||
"naming-format": "Format of name in GMS",
|
||||
"location-format": "Show position on map:",
|
||||
"naming-format": "Show Name:",
|
||||
"publish-location": {
|
||||
"exact": "exact position",
|
||||
"approximate": "approximate position",
|
||||
@ -311,30 +325,19 @@
|
||||
"updated": "format of location for GMS updated"
|
||||
},
|
||||
"publish-name": {
|
||||
"alias-or-initials": "Username or initials",
|
||||
"alias-or-initials-tooltip": "username if exists or Initials of firstname and lastname",
|
||||
"first": "firstname",
|
||||
"first-tooltip": "the firstname only",
|
||||
"first-initial": "firstname and initial",
|
||||
"first-initial-tooltip": "firstname plus initial of lastname",
|
||||
"initials": "Initials of firstname and lastname independent if username exists",
|
||||
"initials-tooltip": "Initials of firstname and lastname independent if username exists",
|
||||
"name-full": "fullname",
|
||||
"name-full-tooltip": "fullname: firstname plus lastname",
|
||||
"updated": "format of name for GMS updated"
|
||||
},
|
||||
"switch": "Allow data export to GMS"
|
||||
}
|
||||
},
|
||||
"hideAmountGDD": "Your GDD amount is hidden.",
|
||||
"hideAmountGDT": "Your GDT amount is hidden.",
|
||||
"humhub": {
|
||||
"delete-disabled": "The user account can only be deleted in the profile menu of the cooperation platform.",
|
||||
"disabled": "Data not exported into the Gradido Community",
|
||||
"enabled": "Data exported into the Gradido Community",
|
||||
"naming-format": "Format of name in the Gradido Community",
|
||||
"naming-format": "Show Name:",
|
||||
"publish-name": {
|
||||
"updated": "Format of name for the Gradido Community updated."
|
||||
},
|
||||
"switch": "Allow data export into the Gradido Community."
|
||||
}
|
||||
},
|
||||
"info": "Transactions can now be made by username or email address.",
|
||||
"language": {
|
||||
@ -374,20 +377,16 @@
|
||||
"subtitle": "If you have forgotten your password, you can reset it here."
|
||||
},
|
||||
"publish-name": {
|
||||
"none": "None",
|
||||
"none-tooltip": "first name and last name are empty",
|
||||
"first": "first name",
|
||||
"first-tooltip": "the first name only",
|
||||
"first-initial": "first name and initial",
|
||||
"first-initial-tooltip": "first name plus initial of last name",
|
||||
"last": "last name",
|
||||
"last-tooltip": "last name only",
|
||||
"last-initial": "initial and last name",
|
||||
"last-initial-tooltip": "First letter of the first name plus last name",
|
||||
"initials": "initials",
|
||||
"initials-tooltip": "Initials of first name and last name",
|
||||
"full": "full name",
|
||||
"full-tooltip": "full name: firstname plus lastname"
|
||||
"alias-or-initials": "Username or initials (Default)",
|
||||
"alias-or-initials-tooltip": "username if exists or Initials of firstname and lastname",
|
||||
"first": "firstname",
|
||||
"first-tooltip": "the firstname only",
|
||||
"first-initial": "firstname and initial",
|
||||
"first-initial-tooltip": "firstname plus initial of lastname",
|
||||
"initials": "Initials",
|
||||
"initials-tooltip": "Initials of firstname and lastname independent if username exists",
|
||||
"name-full": "firstname and lastname",
|
||||
"name-full-tooltip": "fullname: firstname plus lastname"
|
||||
},
|
||||
"showAmountGDD": "Your GDD amount is visible.",
|
||||
"showAmountGDT": "Your GDT amount is visible.",
|
||||
|
||||
71
frontend/src/pages/Circles.vue
Normal file
71
frontend/src/pages/Circles.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="circles">
|
||||
<b-container class="bg-white appBoxShadow gradido-border-radius p-4 mt--3">
|
||||
<div class="h3">{{ $t('circles.headline') }}</div>
|
||||
<div class="my-4 text-small">
|
||||
<span v-for="(line, lineNumber) of $t('circles.text').split('\n')" v-bind:key="lineNumber">
|
||||
{{ line }}
|
||||
<br />
|
||||
</span>
|
||||
</div>
|
||||
<b-row class="my-5">
|
||||
<b-col cols="12">
|
||||
<div class="text-lg-right">
|
||||
<b-button
|
||||
v-if="this.humhubAllowed"
|
||||
variant="gradido"
|
||||
:disabled="this.enableButton === false"
|
||||
@click="authenticateHumhubAutoLogin"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $t('circles.button') }}
|
||||
</b-button>
|
||||
<RouterLink v-else to="/settings/extern">
|
||||
<b-button variant="gradido">
|
||||
{{ $t('circles.button') }}
|
||||
</b-button>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { authenticateHumhubAutoLogin } from '@/graphql/queries'
|
||||
export default {
|
||||
name: 'Circles',
|
||||
data() {
|
||||
return {
|
||||
enableButton: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
humhubAllowed() {
|
||||
return this.$store.state.humhubAllowed
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async authenticateHumhubAutoLogin() {
|
||||
this.enableButton = false
|
||||
this.humhubUri = null
|
||||
this.$apollo
|
||||
.query({
|
||||
query: authenticateHumhubAutoLogin,
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
.then(async (result) => {
|
||||
window.open(result.data.authenticateHumhubAutoLogin, '_blank')
|
||||
this.enableButton = true
|
||||
})
|
||||
.catch(() => {
|
||||
// this.toastError('authenticateHumhubAutoLogin failed!')
|
||||
this.enableButton = true
|
||||
// something went wrong with login link so we disable humhub
|
||||
this.$store.commit('humhubAllowed', false)
|
||||
this.$router.push('/settings/extern')
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -22,12 +22,17 @@ describe('Settings', () => {
|
||||
email: 'john.doe@test.com',
|
||||
language: 'en',
|
||||
newsletterState: false,
|
||||
gmsAllowed: false,
|
||||
humhubAllowed: false,
|
||||
},
|
||||
commit: storeCommitMock,
|
||||
},
|
||||
$apollo: {
|
||||
mutate: mockAPIcall,
|
||||
},
|
||||
$route: {
|
||||
params: {},
|
||||
},
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="card bg-white gradido-border-radius appBoxShadow p-4 mt--3">
|
||||
<b-tabs content-class="mt-3">
|
||||
<b-tab :title="$t('PersonalDetails')" active>
|
||||
<b-tabs v-model="tabIndex" content-class="mt-3">
|
||||
<b-tab :title="$t('PersonalDetails')">
|
||||
<div class="h2">{{ $t('PersonalDetails') }}</div>
|
||||
<div class="my-4 text-small">
|
||||
{{ $t('settings.info') }}
|
||||
@ -79,35 +79,64 @@
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-tab>
|
||||
<div v-if="isExternService">
|
||||
<b-tab :title="$t('ExternServices')">
|
||||
<div class="h2">{{ $t('ExternServices') }}</div>
|
||||
<div v-if="isGMS">
|
||||
<div class="h3">{{ $t('GMS') }}</div>
|
||||
<b-row class="mb-3">
|
||||
<div v-if="isCommunityService">
|
||||
<b-tab class="community-service-tabs" :title="$t('settings.community')">
|
||||
<div class="h2">{{ $t('settings.allow-community-services') }}</div>
|
||||
<div v-if="isHumhub" class="mt-3">
|
||||
<b-row>
|
||||
<b-col cols="12" md="6" lg="6">
|
||||
{{ $t('settings.GMS.switch') }}
|
||||
<div class="text-small">
|
||||
{{ gmsAllowed ? $t('settings.GMS.enabled') : $t('settings.GMS.disabled') }}
|
||||
</div>
|
||||
<div class="h3">{{ $t('Humhub.title') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="12" md="6" lg="6" class="text-right">
|
||||
<user-settings-switch
|
||||
@valueChanged="humhubStateSwitch"
|
||||
:initialValue="$store.state.humhubAllowed"
|
||||
:attrName="'humhubAllowed'"
|
||||
:disabled="isHumhubActivated"
|
||||
:enabledText="$t('settings.humhub.enabled')"
|
||||
:disabledText="$t('settings.humhub.disabled')"
|
||||
:notAllowedText="$t('settings.humhub.delete-disabled')"
|
||||
/>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<div class="h4">{{ $t('Humhub.desc') }}</div>
|
||||
<b-row v-if="humhubAllowed" class="mb-4 humhub-publish-name-row">
|
||||
<b-col cols="12" md="6" lg="6">
|
||||
{{ $t('settings.humhub.naming-format') }}
|
||||
</b-col>
|
||||
<b-col cols="12" md="6" lg="6">
|
||||
<user-naming-format
|
||||
:initialValue="$store.state.humhubPublishName"
|
||||
:attrName="'humhubPublishName'"
|
||||
:successMessage="$t('settings.humhub.publish-name.updated')"
|
||||
/>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
<div v-if="isGMS" class="mt-3">
|
||||
<b-row>
|
||||
<b-col cols="12" md="6" lg="6">
|
||||
<div class="h3 text-muted">{{ $t('GMS.title') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="12" md="6" lg="6" class="text-right">
|
||||
<user-settings-switch
|
||||
@valueChanged="gmsStateSwitch"
|
||||
:initialValue="$store.state.gmsAllowed"
|
||||
:attrName="'gmsAllowed'"
|
||||
:disabled="true"
|
||||
:enabledText="$t('settings.GMS.enabled')"
|
||||
:disabledText="$t('settings.GMS.disabled')"
|
||||
/>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<div class="h4 mt-3 text-muted">{{ $t('GMS.desc') }}</div>
|
||||
<div v-if="gmsAllowed">
|
||||
<b-row class="mb-4">
|
||||
<b-col cols="12" md="6" lg="6">
|
||||
{{ $t('settings.GMS.naming-format') }}
|
||||
</b-col>
|
||||
<b-col cols="12" md="6" lg="6">
|
||||
<user-g-m-s-naming-format
|
||||
<user-naming-format
|
||||
:initialValue="$store.state.gmsPublishName"
|
||||
:attrName="'gmsPublishName'"
|
||||
:successMessage="$t('settings.GMS.publish-name.updated')"
|
||||
@ -132,40 +161,6 @@
|
||||
</b-row>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isHumhub">
|
||||
<div class="h3">{{ $t('Humhub') }}</div>
|
||||
<b-row class="mb-3">
|
||||
<b-col cols="12" md="6" lg="6">
|
||||
{{ $t('settings.humhub.switch') }}
|
||||
<div class="text-small">
|
||||
{{
|
||||
humhubAllowed ? $t('settings.humhub.enabled') : $t('settings.humhub.disabled')
|
||||
}}
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col cols="12" md="6" lg="6" class="text-right">
|
||||
<user-settings-switch
|
||||
@valueChanged="humhubStateSwitch"
|
||||
:initialValue="$store.state.humhubAllowed"
|
||||
:attrName="'humhubAllowed'"
|
||||
:enabledText="$t('settings.humhub.enabled')"
|
||||
:disabledText="$t('settings.humhub.disabled')"
|
||||
/>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row v-if="humhubAllowed" class="mb-4">
|
||||
<b-col cols="12" md="6" lg="6">
|
||||
{{ $t('settings.humhub.naming-format') }}
|
||||
</b-col>
|
||||
<b-col cols="12" md="6" lg="6">
|
||||
<user-naming-format
|
||||
:initialValue="$store.state.humhubPublishName"
|
||||
:attrName="'humhubPublishName'"
|
||||
:successMessage="$t('settings.humhub.publish-name.updated')"
|
||||
/>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</b-tab>
|
||||
</div>
|
||||
</b-tabs>
|
||||
@ -180,7 +175,6 @@
|
||||
</template>
|
||||
<script>
|
||||
import UserNamingFormat from '@/components/UserSettings/UserNamingFormat'
|
||||
import UserGMSNamingFormat from '@/components/UserSettings/UserGMSNamingFormat'
|
||||
import UserGMSLocationFormat from '@/components/UserSettings/UserGMSLocationFormat'
|
||||
import UserGMSLocation from '@/components/UserSettings/UserGMSLocation'
|
||||
import UserName from '@/components/UserSettings/UserName.vue'
|
||||
@ -195,7 +189,6 @@ export default {
|
||||
name: 'Profile',
|
||||
components: {
|
||||
UserNamingFormat,
|
||||
UserGMSNamingFormat,
|
||||
UserGMSLocationFormat,
|
||||
UserGMSLocation,
|
||||
UserName,
|
||||
@ -222,6 +215,10 @@ export default {
|
||||
} = state
|
||||
|
||||
const username = this.$store.state.username || ''
|
||||
let tabIndex = 0
|
||||
if (this.$route.params.tabAlias === 'extern') {
|
||||
tabIndex = 1
|
||||
}
|
||||
|
||||
return {
|
||||
darkMode,
|
||||
@ -234,6 +231,7 @@ export default {
|
||||
humhubAllowed,
|
||||
mutation: '',
|
||||
variables: {},
|
||||
tabIndex,
|
||||
}
|
||||
},
|
||||
|
||||
@ -242,14 +240,17 @@ export default {
|
||||
const { firstName, lastName } = this.$store.state
|
||||
return firstName === this.firstName && lastName === this.lastName
|
||||
},
|
||||
isExternService() {
|
||||
isHumhubActivated() {
|
||||
return this.humhubAllowed
|
||||
},
|
||||
isCommunityService() {
|
||||
return this.isGMS || this.isHumhub
|
||||
},
|
||||
isGMS() {
|
||||
return CONFIG.GMS_ACTIVE
|
||||
},
|
||||
isHumhub() {
|
||||
return CONFIG.HUMHUB_ACTIVE && this.username
|
||||
return CONFIG.HUMHUB_ACTIVE
|
||||
},
|
||||
},
|
||||
// TODO: watch: {
|
||||
@ -286,6 +287,9 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.community-service-tabs {
|
||||
min-height: 315px;
|
||||
}
|
||||
.card-border-radius {
|
||||
border-radius: 0px 5px 5px 0px !important;
|
||||
}
|
||||
|
||||
@ -49,8 +49,8 @@ describe('router', () => {
|
||||
expect(routes.find((r) => r.path === '/').redirect()).toEqual({ path: '/login' })
|
||||
})
|
||||
|
||||
it('has 20 routes defined', () => {
|
||||
expect(routes).toHaveLength(20)
|
||||
it('has 21 routes defined', () => {
|
||||
expect(routes).toHaveLength(21)
|
||||
})
|
||||
|
||||
describe('overview', () => {
|
||||
|
||||
@ -88,6 +88,14 @@ const routes = [
|
||||
pageTitle: 'usersearch',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/circles',
|
||||
component: () => import('@/pages/Circles'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
pageTitle: 'circles',
|
||||
},
|
||||
},
|
||||
// {
|
||||
// path: '/storys',
|
||||
// component: () => import('@/pages/TopStorys'),
|
||||
@ -103,7 +111,7 @@ const routes = [
|
||||
// },
|
||||
// },
|
||||
{
|
||||
path: '/settings',
|
||||
path: '/settings/:tabAlias?',
|
||||
component: () => import('@/pages/Settings'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user