feat(console): change my username (#2587)

* feat: username change

* use btn, update on dist

* disable mgmt side

* lint

* rm scope

* chore(deps-dev): bump eslint from 7.32.0 to 8.1.0 in /console (#2569)

Bumps [eslint](https://github.com/eslint/eslint) from 7.32.0 to 8.1.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v7.32.0...v8.1.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump ts-node from 10.2.1 to 10.4.0 in /console (#2568)

Bumps [ts-node](https://github.com/TypeStrong/ts-node) from 10.2.1 to 10.4.0.
- [Release notes](https://github.com/TypeStrong/ts-node/releases)
- [Commits](https://github.com/TypeStrong/ts-node/compare/v10.2.1...v10.4.0)

---
updated-dependencies:
- dependency-name: ts-node
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @types/node from 16.10.2 to 16.11.4 in /console (#2567)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 16.10.2 to 16.11.4.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* cli core

* material, cdk

* eslint schematics

* legacy peer deps

* grpcweb, types

* dontgrade eslint

* revert package mods

* change username mgmt

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
Max Peintner
2021-11-02 09:03:02 +01:00
committed by GitHub
parent bc526561d0
commit 5ba1e45423
13 changed files with 782 additions and 647 deletions

View File

@@ -80,10 +80,7 @@ const authConfig: AuthConfig = {
};
@NgModule({
declarations: [
AppComponent,
SignedoutComponent,
],
declarations: [AppComponent, SignedoutComponent],
imports: [
AppRoutingModule,
CommonModule,
@@ -91,7 +88,12 @@ const authConfig: AuthConfig = {
OverlayModule,
OAuthModule.forRoot({
resourceServer: {
allowedUrls: ['https://test.api.zitadel.caos.ch/caos.zitadel.auth.api.v1.AuthService', 'https://test.api.zitadel.caos.ch/oauth/v2/userinfo', 'https://test.api.zitadel.caos.ch/caos.zitadel.management.api.v1.ManagementService/', 'https://preview.api.zitadel.caos.ch'],
allowedUrls: [
'https://test.api.zitadel.caos.ch/caos.zitadel.auth.api.v1.AuthService',
'https://test.api.zitadel.caos.ch/oauth/v2/userinfo',
'https://test.api.zitadel.caos.ch/caos.zitadel.management.api.v1.ManagementService/',
'https://preview.api.zitadel.caos.ch',
],
sendAccessToken: true,
},
}),
@@ -185,7 +187,6 @@ const authConfig: AuthConfig = {
],
bootstrap: [AppComponent],
})
export class AppModule {
constructor() {}
}

View File

@@ -16,21 +16,24 @@
<cnsl-info-row *ngIf="user" [user]="user"></cnsl-info-row>
<cnsl-card *ngIf="user && user.human && user.human.profile" class=" app-card" title="{{ 'USER.PROFILE.TITLE' | translate }}">
<cnsl-detail-form [showEditImage]="true" [preferredLoginName]="user.preferredLoginName" [genders]="genders" [languages]="languages" [username]="user.userName" [user]="user.human"
(changedLanguage)="changedLanguage($event)" (submitData)="saveProfile($event)">
<cnsl-card *ngIf="user && user.human && user.human.profile" class=" app-card"
title="{{ 'USER.PROFILE.TITLE' | translate }}">
<cnsl-detail-form [showEditImage]="true" [preferredLoginName]="user.preferredLoginName" [genders]="genders"
[languages]="languages" [username]="user.userName" [user]="user.human"
(changedLanguage)="changedLanguage($event)" (changeUsernameClicked)="changeUsername()"
(submitData)="saveProfile($event)">
</cnsl-detail-form>
</cnsl-card>
<cnsl-card *ngIf="user" title="{{ 'USER.LOGINMETHODS.TITLE' | translate }}"
description="{{ 'USER.LOGINMETHODS.DESCRIPTION' | translate }}">
<button class="icon-button" card-actions mat-icon-button (click)="refreshUser()" matTooltip="{{'ACTIONS.REFRESH' | translate}}">
<button class="icon-button" card-actions mat-icon-button (click)="refreshUser()"
matTooltip="{{'ACTIONS.REFRESH' | translate}}">
<mat-icon class="icon">refresh</mat-icon>
</button>
<cnsl-contact *ngIf="user.human" [human]="user.human" [state]="user.state" [canWrite]="true"
(editType)="openEditDialog($event)" (enteredPhoneCode)="enteredPhoneCode($event)"
(deletedPhone)="deletePhone()" (resendEmailVerification)="resendEmailVerification()"
(resendPhoneVerification)="resendPhoneVerification()">
(editType)="openEditDialog($event)" (enteredPhoneCode)="enteredPhoneCode($event)" (deletedPhone)="deletePhone()"
(resendEmailVerification)="resendEmailVerification()" (resendPhoneVerification)="resendPhoneVerification()">
</cnsl-contact>
</cnsl-card>

View File

@@ -58,6 +58,32 @@ export class AuthUserDetailComponent implements OnDestroy {
this.subscription.unsubscribe();
}
public changeUsername(): void {
const dialogRefPhone = this.dialog.open(EditDialogComponent, {
data: {
confirmKey: 'ACTIONS.CHANGE',
cancelKey: 'ACTIONS.CANCEL',
labelKey: 'ACTIONS.NEWVALUE',
titleKey: 'USER.PROFILE.CHANGEUSERNAME_TITLE',
descriptionKey: 'USER.PROFILE.CHANGEUSERNAME_DESC',
value: this.user.userName,
},
width: '400px',
});
dialogRefPhone.afterClosed().subscribe(resp => {
if (resp && resp !== this.user.userName) {
this.userService.updateMyUserName(resp).then(() => {
this.toast.showInfo('USER.TOAST.USERNAMECHANGED', true);
this.refreshUser();
})
.catch(error => {
this.toast.showError(error);
});
}
});
}
public saveProfile(profileData: Profile.AsObject): void {
if (this.user.human) {
this.user.human.profile = profileData;

View File

@@ -5,16 +5,21 @@
<div class="i-wrapper" *ngIf="showEditImage">
<i class="las la-camera"></i>
</div>
<cnsl-avatar
*ngIf="user && user.profile?.displayName && user.profile?.firstName && user.profile?.lastName"
class="avatar" [name]="user.profile?.displayName ?? ''" [avatarUrl]="user?.profile?.avatarUrl || ''" [forColor]="preferredLoginName" [size]="80">
<cnsl-avatar *ngIf="user && user.profile?.displayName && user.profile?.firstName && user.profile?.lastName"
class="avatar" [name]="user.profile?.displayName ?? ''" [avatarUrl]="user?.profile?.avatarUrl || ''"
[forColor]="preferredLoginName" [size]="80">
</cnsl-avatar>
</button>
<div className="usernamediv">
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}</cnsl-label>
<input cnslInput formControlName="userName" />
</cnsl-form-field>
<button type="button" color="primary" mat-stroked-button class="edit"
(click)="changeUsername()">{{'USER.PROFILE.CHANGEUSERNAME' |
translate}}</button>
</div>
</div>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}</cnsl-label>

View File

@@ -7,6 +7,22 @@
&.inner {
margin: 0;
width: 100%;
display: flex;
align-items: center;
.usernamediv {
margin-left: .5rem;
margin-bottom: .5rem;
.formfield {
margin: 0;
flex: 1;
}
.edit {
cursor: pointer !important;
}
}
}
.camera-wrapper {

View File

@@ -21,6 +21,7 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
@Input() public languages: string[] = ['de', 'en'];
@Output() public submitData: EventEmitter<Profile.AsObject> = new EventEmitter<Profile.AsObject>();
@Output() public changedLanguage: EventEmitter<string> = new EventEmitter<string>();
@Output() public changeUsernameClicked: EventEmitter<void> = new EventEmitter();
public profileForm!: FormGroup;
@@ -73,6 +74,10 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
this.submitData.emit(this.profileForm.value);
}
public changeUsername(): void {
this.changeUsernameClicked.emit();
}
public openUploadDialog(): void {
const dialogRef = this.dialog.open(ProfilePictureComponent, {
data: {

View File

@@ -48,7 +48,7 @@
<cnsl-card *ngIf="user.human" title="{{ 'USER.PROFILE.TITLE' | translate }}">
<cnsl-detail-form [preferredLoginName]="user.preferredLoginName" [disabled]="(canWrite$ | async) === false"
[genders]="genders" [languages]="languages" [username]="user.userName" [user]="user.human"
(submitData)="saveProfile($event)">
(submitData)="saveProfile($event)" (changeUsernameClicked)="changeUsername()">
</cnsl-detail-form>
</cnsl-card>

View File

@@ -53,22 +53,28 @@ export class UserDetailComponent implements OnInit {
refreshUser(): void {
this.refreshChanges$.emit();
this.route.params.pipe(take(1)).subscribe(params => {
this.route.params.pipe(take(1)).subscribe((params) => {
const { id } = params;
this.mgmtUserService.getUserByID(id).then(resp => {
this.mgmtUserService
.getUserByID(id)
.then((resp) => {
if (resp.user) {
this.user = resp.user;
}
}).catch(err => {
})
.catch((err) => {
this.error = err.message ?? '';
this.toast.showError(err);
});
this.mgmtUserService.listUserMetadata(id, 0, 100, []).then(resp => {
this.mgmtUserService
.listUserMetadata(id, 0, 100, [])
.then((resp) => {
if (resp.resultList) {
this.metadata = resp.resultList;
}
}).catch(err => {
})
.catch((err) => {
console.error(err);
});
});
@@ -78,30 +84,67 @@ export class UserDetailComponent implements OnInit {
this.refreshUser();
}
public changeUsername(): void {
const dialogRefPhone = this.dialog.open(EditDialogComponent, {
data: {
confirmKey: 'ACTIONS.CHANGE',
cancelKey: 'ACTIONS.CANCEL',
labelKey: 'ACTIONS.NEWVALUE',
titleKey: 'USER.PROFILE.CHANGEUSERNAME_TITLE',
descriptionKey: 'USER.PROFILE.CHANGEUSERNAME_DESC',
value: this.user.userName,
},
width: '400px',
});
dialogRefPhone.afterClosed().subscribe((resp) => {
if (resp && resp !== this.user.userName) {
this.mgmtUserService
.updateUserName(this.user.id, resp)
.then(() => {
this.toast.showInfo('USER.TOAST.USERNAMECHANGED', true);
this.refreshUser();
})
.catch((error) => {
this.toast.showError(error);
});
}
});
}
public unlockUser(): void {
const req = new UnlockUserRequest();
req.setId(this.user.id);
this.mgmtUserService.unlockUser(req).then(() => {
this.mgmtUserService
.unlockUser(req)
.then(() => {
this.toast.showInfo('USER.TOAST.UNLOCKED', true);
this.refreshUser();
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
public changeState(newState: UserState): void {
if (newState === UserState.USER_STATE_ACTIVE) {
this.mgmtUserService.reactivateUser(this.user.id).then(() => {
this.mgmtUserService
.reactivateUser(this.user.id)
.then(() => {
this.toast.showInfo('USER.TOAST.REACTIVATED', true);
this.user.state = newState;
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
} else if (newState === UserState.USER_STATE_INACTIVE) {
this.mgmtUserService.deactivateUser(this.user.id).then(() => {
this.mgmtUserService
.deactivateUser(this.user.id)
.then(() => {
this.toast.showInfo('USER.TOAST.DEACTIVATED', true);
this.user.state = newState;
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
@@ -118,12 +161,13 @@ export class UserDetailComponent implements OnInit {
this.user.human.profile.nickName,
this.user.human.profile.displayName,
this.user.human.profile.preferredLanguage,
this.user.human.profile.gender)
this.user.human.profile.gender,
)
.then(() => {
this.toast.showInfo('USER.TOAST.SAVED', true);
this.refreshChanges$.emit();
})
.catch(error => {
.catch((error) => {
this.toast.showError(error);
});
}
@@ -135,59 +179,70 @@ export class UserDetailComponent implements OnInit {
this.user.machine.description = machineData.description;
this.mgmtUserService
.updateMachine(
this.user.id,
this.user.machine.name,
this.user.machine.description)
.updateMachine(this.user.id, this.user.machine.name, this.user.machine.description)
.then(() => {
this.toast.showInfo('USER.TOAST.SAVED', true);
this.refreshChanges$.emit();
})
.catch(error => {
.catch((error) => {
this.toast.showError(error);
});
}
}
public resendEmailVerification(): void {
this.mgmtUserService.resendHumanEmailVerification(this.user.id).then(() => {
this.mgmtUserService
.resendHumanEmailVerification(this.user.id)
.then(() => {
this.toast.showInfo('USER.TOAST.EMAILVERIFICATIONSENT', true);
this.refreshChanges$.emit();
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
public resendPhoneVerification(): void {
this.mgmtUserService.resendHumanPhoneVerification(this.user.id).then(() => {
this.mgmtUserService
.resendHumanPhoneVerification(this.user.id)
.then(() => {
this.toast.showInfo('USER.TOAST.PHONEVERIFICATIONSENT', true);
this.refreshChanges$.emit();
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
public deletePhone(): void {
this.mgmtUserService.removeHumanPhone(this.user.id).then(() => {
this.mgmtUserService
.removeHumanPhone(this.user.id)
.then(() => {
this.toast.showInfo('USER.TOAST.PHONEREMOVED', true);
if (this.user.human) {
this.user.human.phone = new Phone().setPhone('').toObject();
this.refreshUser();
}
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
public saveEmail(email: string): void {
if (this.user.id && email) {
this.mgmtUserService.updateHumanEmail(this.user.id, email).then(() => {
this.mgmtUserService
.updateHumanEmail(this.user.id, email)
.then(() => {
this.toast.showInfo('USER.TOAST.EMAILSAVED', true);
if (this.user.state === UserState.USER_STATE_INITIAL) {
this.mgmtUserService.resendHumanInitialization(this.user.id, email ?? '').then(() => {
this.mgmtUserService
.resendHumanInitialization(this.user.id, email ?? '')
.then(() => {
this.toast.showInfo('USER.TOAST.INITEMAILSENT', true);
this.refreshChanges$.emit();
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
@@ -195,7 +250,8 @@ export class UserDetailComponent implements OnInit {
this.user.human.email = new Email().setEmail(email).toObject();
this.refreshUser();
}
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
@@ -204,13 +260,15 @@ export class UserDetailComponent implements OnInit {
public savePhone(phone: string): void {
if (this.user.id && phone) {
this.mgmtUserService
.updateHumanPhone(this.user.id, phone).then(() => {
.updateHumanPhone(this.user.id, phone)
.then(() => {
this.toast.showInfo('USER.TOAST.PHONESAVED', true);
if (this.user.human) {
this.user.human.phone = new Phone().setPhone(phone).toObject();
this.refreshUser();
}
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
@@ -221,13 +279,13 @@ export class UserDetailComponent implements OnInit {
}
public sendSetPasswordNotification(): void {
this.mgmtUserService.sendHumanResetPasswordNotification(
this.user.id,
SendHumanResetPasswordNotificationRequest.Type.TYPE_EMAIL,
).then(() => {
this.mgmtUserService
.sendHumanResetPasswordNotification(this.user.id, SendHumanResetPasswordNotificationRequest.Type.TYPE_EMAIL)
.then(() => {
this.toast.showInfo('USER.TOAST.PASSWORDNOTIFICATIONSENT', true);
this.refreshChanges$.emit();
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
@@ -243,15 +301,18 @@ export class UserDetailComponent implements OnInit {
width: '400px',
});
dialogRef.afterClosed().subscribe(resp => {
dialogRef.afterClosed().subscribe((resp) => {
if (resp) {
this.mgmtUserService.removeUser(this.user.id).then(() => {
this.mgmtUserService
.removeUser(this.user.id)
.then(() => {
const params: Params = {
'deferredReload': true,
deferredReload: true,
};
this.router.navigate(['/users/list', this.user.human ? 'humans' : 'machines'], { queryParams: params });
this.toast.showInfo('USER.TOAST.DELETED', true);
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
@@ -263,12 +324,15 @@ export class UserDetailComponent implements OnInit {
width: '400px',
});
dialogRef.afterClosed().subscribe(resp => {
dialogRef.afterClosed().subscribe((resp) => {
if (resp.send && this.user.id) {
this.mgmtUserService.resendHumanInitialization(this.user.id, resp.email ?? '').then(() => {
this.mgmtUserService
.resendHumanInitialization(this.user.id, resp.email ?? '')
.then(() => {
this.toast.showInfo('USER.TOAST.INITEMAILSENT', true);
this.refreshChanges$.emit();
}).catch(error => {
})
.catch((error) => {
this.toast.showError(error);
});
}
@@ -291,7 +355,7 @@ export class UserDetailComponent implements OnInit {
width: '400px',
});
dialogRefPhone.afterClosed().subscribe(resp => {
dialogRefPhone.afterClosed().subscribe((resp) => {
if (resp) {
this.savePhone(resp);
}
@@ -311,7 +375,7 @@ export class UserDetailComponent implements OnInit {
width: '400px',
});
dialogRefEmail.afterClosed().subscribe(resp => {
dialogRefEmail.afterClosed().subscribe((resp) => {
if (resp) {
this.saveEmail(resp);
}

View File

@@ -68,6 +68,8 @@ import {
UpdateMyPasswordResponse,
UpdateMyProfileRequest,
UpdateMyProfileResponse,
UpdateMyUserNameRequest,
UpdateMyUserNameResponse,
VerifyMyAuthFactorOTPRequest,
VerifyMyAuthFactorOTPResponse,
VerifyMyAuthFactorU2FRequest,
@@ -407,6 +409,12 @@ export class GrpcAuthService {
).then(resp => resp.toObject());
}
public updateMyUserName(username: string): Promise<UpdateMyUserNameResponse.AsObject> {
const req = new UpdateMyUserNameRequest();
req.setUserName(username);
return this.grpcService.auth.updateMyUserName(req, null).then(resp => resp.toObject());
}
public listMyZitadelPermissions(): Promise<ListMyZitadelPermissionsResponse.AsObject> {
return this.grpcService.auth.listMyZitadelPermissions(
new ListMyZitadelPermissionsRequest(), null,

View File

@@ -30,8 +30,10 @@ export class GrpcService {
) {}
public async loadAppEnvironment(): Promise<any> {
return this.http.get('./assets/environment.json')
.toPromise().then((data: any) => {
return this.http
.get('./assets/environment.json')
.toPromise()
.then((data: any) => {
if (data && data.authServiceUrl && data.mgmtServiceUrl && data.issuer) {
const interceptors = {
unaryInterceptors: [
@@ -74,7 +76,8 @@ export class GrpcService {
this.authenticationService.initConfig(authConfig);
}
return Promise.resolve(data);
}).catch(() => {
})
.catch(() => {
console.error('Failed to load environment from assets');
});
}

File diff suppressed because it is too large Load Diff

View File

@@ -339,6 +339,9 @@
"EMAIL": "E-Mail",
"PHONE": "Telefonnummer",
"USERNAME": "Benutzername",
"CHANGEUSERNAME":"bearbeiten",
"CHANGEUSERNAME_TITLE":"Benutzername ändern",
"CHANGEUSERNAME_DESC":"Geben Sie ihren neuen Namen an.",
"FIRSTNAME": "Vorname",
"LASTNAME": "Nachname",
"NICKNAME": "Spitzname",
@@ -473,6 +476,7 @@
"TOAST": {
"CREATED": "Benutzer erfolgreich erstellt.",
"SAVED": "Profil gespeichert.",
"USERNAMECHANGED":"Username geändert.",
"EMAILSAVED": "E-Mail gespeichert.",
"INITEMAILSENT": "Initialisierung Email gesendet.",
"PHONESAVED": "Telefonnummer gespeichert.",

View File

@@ -339,6 +339,9 @@
"EMAIL": "E-mail",
"PHONE": "Phonenumber",
"USERNAME": "User Name",
"CHANGEUSERNAME":"modify",
"CHANGEUSERNAME_TITLE":"Change username",
"CHANGEUSERNAME_DESC":"Enter the new name in the field below.",
"FIRSTNAME": "First Name",
"LASTNAME": "Last Name",
"NICKNAME": "Nickname",
@@ -473,6 +476,7 @@
"TOAST": {
"CREATED": "User created successfully.",
"SAVED": "Profile saved successfully.",
"USERNAMECHANGED":"Username changed.",
"EMAILSAVED": "E-mail saved successfully.",
"INITEMAILSENT": "Initializing mail sent.",
"PHONESAVED": "Phone saved successfully.",