Merge branch 'master' into overview_circles

This commit is contained in:
einhornimmond 2024-05-10 15:19:54 +02:00
commit 8abd5404bf
10 changed files with 109 additions and 27 deletions

View File

@ -1,4 +1,3 @@
import { User } from '@entity/User'
import { SignJWT } from 'jose'
import { IRequestOptions, IRestResponse, RestClient } from 'typed-rest-client'
@ -6,6 +5,7 @@ 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'
@ -59,9 +59,8 @@ export class HumHubClient {
return token
}
public async createAutoLoginUrl(user: User) {
public async createAutoLoginUrl(username: string) {
const secret = new TextEncoder().encode(CONFIG.HUMHUB_JWT_KEY)
const username = user.alias ?? user.gradidoID
logger.info(`user ${username} as username for humhub auto-login`)
const token = await new SignJWT({ username })
.setProtectedHeader({ alg: 'HS256' })
@ -109,6 +108,11 @@ export class HumHubClient {
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
@ -130,7 +134,7 @@ export class HumHubClient {
* @param user for saving on humhub instance
*/
public async createUser(user: PostUser): Promise<void> {
logger.info('create new humhub user', user)
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)
@ -153,7 +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', user)
logger.info('update humhub user', new PostUserLoggingView(user))
const options = await this.createRequestOptions()
const response = await this.restClient.update<GetUser>(
`/api/v1/user/${humhubUserId}`,

View 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,
}
}
}

View 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,
},
}
}
}

View 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) + '...',
}
}
}

View File

@ -168,7 +168,7 @@ export class UserResolver {
let humhubUserPromise: Promise<IRestResponse<GetUser>> | undefined
const klicktippStatePromise = getKlicktippState(dbUser.emailContact.email)
if (CONFIG.HUMHUB_ACTIVE && dbUser.humhubAllowed) {
humhubUserPromise = HumHubClient.getInstance()?.userByEmailAsync(email)
humhubUserPromise = HumHubClient.getInstance()?.userByUsernameAsync(email)
}
if (dbUser.passwordEncryptionType !== PasswordEncryptionType.GRADIDO_ID) {
@ -726,7 +726,15 @@ export class UserResolver {
if (!humhubClient) {
throw new LogError('cannot create humhub client')
}
return await humhubClient.createAutoLoginUrl(dbUser)
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])

View File

@ -28,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)

View File

@ -17,6 +17,9 @@ describe('Sidebar', () => {
roles: [],
},
},
$route: {
path: '/',
},
}
const Wrapper = () => {
@ -33,8 +36,8 @@ describe('Sidebar', () => {
})
describe('the general section', () => {
it('has eight nav-items', () => {
expect(wrapper.findAll('ul').at(0).findAll('.nav-item')).toHaveLength(8)
it('has seven nav-items', () => {
expect(wrapper.findAll('ul').at(0).findAll('.nav-item')).toHaveLength(7)
})
it('has nav-item "navigation.overview" in navbar', () => {
@ -53,20 +56,16 @@ describe('Sidebar', () => {
expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('creation')
})
it('has nav-item "GDT" in navbar', () => {
expect(wrapper.findAll('.nav-item').at(4).text()).toContain('GDT')
})
it('has nav-item "navigation.info" in navbar', () => {
expect(wrapper.findAll('.nav-item').at(5).text()).toContain('navigation.info')
expect(wrapper.findAll('.nav-item').at(4).text()).toContain('navigation.info')
})
it('has nav-item "navigation.circles" in navbar', () => {
expect(wrapper.findAll('.nav-item').at(6).text()).toContain('navigation.circles')
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(7).text()).toContain('navigation.usersearch')
expect(wrapper.findAll('.nav-item').at(6).text()).toContain('navigation.usersearch')
})
})

View File

@ -16,7 +16,7 @@
<b-icon icon="cash" aria-hidden="true"></b-icon>
<span class="ml-2">{{ $t('navigation.send') }}</span>
</b-nav-item>
<b-nav-item to="/transactions" class="mb-3" active-class="activeRoute">
<b-nav-item to="/transactions" :class="transactionClass" active-class="activeRoute">
<b-img src="/img/svg/transaction.svg" height="20" class="svg-icon" />
<span class="ml-2">{{ $t('navigation.transactions') }}</span>
</b-nav-item>
@ -24,10 +24,6 @@
<b-img src="/img/svg/community.svg" height="20" class="svg-icon" />
<span class="ml-2">{{ $t('creation') }}</span>
</b-nav-item>
<b-nav-item to="/gdt" class="mb-3" active-class="activeRoute">
<b-icon icon="layers" aria-hidden="true"></b-icon>
<span class="ml-2">{{ $t('GDT') }}</span>
</b-nav-item>
<b-nav-item to="/information" class="mb-3" active-class="activeRoute">
<b-img src="/img/svg/info.svg" height="20" class="svg-icon" />
<span class="ml-2">{{ $t('navigation.info') }}</span>
@ -86,6 +82,14 @@ export default {
props: {
shadow: { type: Boolean, required: false, default: true },
},
computed: {
transactionClass() {
if (this.$route.path === '/gdt') {
return 'mb-3 activeRoute'
}
return 'mb-3'
},
},
}
</script>
<style>

View File

@ -59,8 +59,11 @@ export default {
this.enableButton = true
})
.catch(() => {
this.toastError('authenticateHumhubAutoLogin failed!')
// 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')
})
},
},

View File

@ -80,9 +80,9 @@
</b-row>
</b-tab>
<div v-if="isCommunityService">
<b-tab :title="$t('settings.community')">
<b-tab class="community-service-tabs" :title="$t('settings.community')">
<div class="h2">{{ $t('settings.allow-community-services') }}</div>
<div v-if="isHumhub" class="">
<div v-if="isHumhub" class="mt-3">
<b-row>
<b-col cols="12" md="6" lg="6">
<div class="h3">{{ $t('Humhub.title') }}</div>
@ -113,7 +113,7 @@
</b-col>
</b-row>
</div>
<div v-if="isGMS">
<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>
@ -129,7 +129,7 @@
/>
</b-col>
</b-row>
<div class="h4 mt-3">{{ $t('GMS.desc') }}</div>
<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">
@ -287,6 +287,9 @@ export default {
}
</script>
<style>
.community-service-tabs {
min-height: 315px;
}
.card-border-radius {
border-radius: 0px 5px 5px 0px !important;
}