mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 00:17:32 +00:00
feat: allow global org users to create org and self delete (#2759)
* fix: grant PROJECT_OWNER_VIEWER_GLOBAL org.create permission * Update authz.yaml * feat: delete my user * console things * lint * signout after deletion * stylelint rule * Update authz.yaml * Update authz.yaml * setup step * role SELF_MANAGEMENT_GLOBAL setup * fix: change default role on global org * Apply suggestions from code review Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * Update console/src/assets/i18n/it.json Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
@@ -1,18 +1,18 @@
|
||||
<div class="card" [ngClass]="{'nomargin': nomargin}">
|
||||
<div *ngIf="title || description" class="header" [ngClass]="{'bottom-margin': expanded}">
|
||||
<div *ngIf="title" class="row">
|
||||
<h2 class="title">{{title}}</h2>
|
||||
<span class="fill-space"></span>
|
||||
<ng-content select="[card-actions]"></ng-content>
|
||||
<button class="button" type="button" matTooltip="Expand or collapse" mat-icon-button
|
||||
(click)="expanded = !expanded">
|
||||
<mat-icon *ngIf="!expanded">keyboard_arrow_down</mat-icon>
|
||||
<mat-icon *ngIf="expanded">keyboard_arrow_up</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<p *ngIf="description" class="desc">{{description}}</p>
|
||||
</div>
|
||||
<div class="card-content" *ngIf="expanded" [@openClose]="animate">
|
||||
<ng-content></ng-content>
|
||||
<div class="card" [ngClass]="{'nomargin': nomargin, 'warn': warn}">
|
||||
<div *ngIf="title || description" class="header" [ngClass]="{'bottom-margin': expanded}">
|
||||
<div *ngIf="title" class="row">
|
||||
<h2 class="title">{{title}}</h2>
|
||||
<span class="fill-space"></span>
|
||||
<ng-content select="[card-actions]"></ng-content>
|
||||
<button class="button" type="button" matTooltip="Expand or collapse" mat-icon-button
|
||||
(click)="expanded = !expanded">
|
||||
<mat-icon *ngIf="!expanded">keyboard_arrow_down</mat-icon>
|
||||
<mat-icon *ngIf="expanded">keyboard_arrow_up</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<p *ngIf="description" class="desc">{{description}}</p>
|
||||
</div>
|
||||
<div class="card-content" *ngIf="expanded" [@openClose]="animate">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
</div>
|
@@ -11,14 +11,13 @@ import { Component, Input } from '@angular/core';
|
||||
style({ height: '0', opacity: 0 }),
|
||||
animate('150ms ease-in-out', style({ height: '*', opacity: 1 })),
|
||||
]),
|
||||
transition(':leave', [
|
||||
animate('150ms ease-in-out', style({ height: '0', opacity: 0 })),
|
||||
]),
|
||||
transition(':leave', [animate('150ms ease-in-out', style({ height: '0', opacity: 0 }))]),
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class CardComponent {
|
||||
@Input() public expanded: boolean = true;
|
||||
@Input() public warn: boolean = false;
|
||||
@Input() public title: string = '';
|
||||
@Input() public description: string = '';
|
||||
@Input() public animate: boolean = false;
|
||||
|
@@ -7,19 +7,23 @@
|
||||
$background: map-get($theme, background);
|
||||
$card-background-color: mat.get-color-from-palette($background, card);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$border-color: if($is-dark-theme, rgba(#8795a1, .2), rgba(#8795a1, .2));
|
||||
$border-color: if($is-dark-theme, rgba(#8795a1, 0.2), rgba(#8795a1, 0.2));
|
||||
$border-selected-color: if($is-dark-theme, #ffffff, #000000);
|
||||
/* stylelint-enable */
|
||||
|
||||
.card {
|
||||
background-color: $card-background-color;
|
||||
transition: background-color .3s cubic-bezier(.645, .045, .355, 1);
|
||||
transition: background-color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
border: 1px solid $border-color;
|
||||
box-sizing: border-box;
|
||||
border-radius: .5rem;
|
||||
border-radius: 0.5rem;
|
||||
outline: none;
|
||||
height: 100%;
|
||||
|
||||
&.warn {
|
||||
border-color: var(--warn);
|
||||
}
|
||||
|
||||
.selection-icon {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
|
@@ -55,6 +55,17 @@
|
||||
<ng-template cnslHasFeature [hasFeature]="['metadata.user']">
|
||||
<cnsl-metadata *ngIf="user?.id" [userId]="user.id"></cnsl-metadata>
|
||||
</ng-template>
|
||||
|
||||
<ng-template cnslHasRole [hasRole]="['user.self.delete']">
|
||||
<cnsl-card title="{{'USER.PAGES.DELETEACCOUNT'| translate}}" [warn]="true">
|
||||
<p>{{'USER.PAGES.DELETEACCOUNT_DESC'| translate}}</p>
|
||||
|
||||
<div class="delete-account-wrapper">
|
||||
<button color="warn" mat-raised-button (click)="deleteAccount()">{{'USER.PAGES.DELETEACCOUNT_BTN' |
|
||||
translate}}</button>
|
||||
</div>
|
||||
</cnsl-card>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<div *ngIf="user" class="side" metainfo>
|
||||
|
@@ -60,3 +60,8 @@
|
||||
.side-padding {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.delete-account-wrapper {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
@@ -4,7 +4,9 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import { UserGrantContext } from 'src/app/modules/user-grants/user-grants-datasource';
|
||||
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||
import { Email, Gender, Phone, Profile, User, UserState } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { AuthenticationService } from 'src/app/services/authentication.service';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@@ -36,6 +38,7 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
private toast: ToastService,
|
||||
public userService: GrpcAuthService,
|
||||
private dialog: MatDialog,
|
||||
private auth: AuthenticationService,
|
||||
) {
|
||||
this.loading = true;
|
||||
this.refreshUser();
|
||||
@@ -252,4 +255,30 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public deleteAccount(): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'USER.DIALOG.DELETE_BTN',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'USER.DIALOG.DELETE_TITLE',
|
||||
descriptionKey: 'USER.DIALOG.DELETE_AUTH_DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((resp) => {
|
||||
if (resp) {
|
||||
this.userService
|
||||
.RemoveMyUser()
|
||||
.then(() => {
|
||||
this.toast.showInfo('USER.PAGES.DELETEACCOUNT_SUCCESS', true);
|
||||
this.auth.signout();
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -56,6 +56,8 @@ import {
|
||||
RemoveMyPasswordlessResponse,
|
||||
RemoveMyPhoneRequest,
|
||||
RemoveMyPhoneResponse,
|
||||
RemoveMyUserRequest,
|
||||
RemoveMyUserResponse,
|
||||
ResendMyEmailVerificationRequest,
|
||||
ResendMyEmailVerificationResponse,
|
||||
ResendMyPhoneVerificationRequest,
|
||||
@@ -400,6 +402,11 @@ export class GrpcAuthService {
|
||||
return this.grpcService.auth.listMyMemberships(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public RemoveMyUser(): Promise<RemoveMyUserResponse.AsObject> {
|
||||
const req = new RemoveMyUserRequest();
|
||||
return this.grpcService.auth.removeMyUser(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getMyEmail(): Promise<GetMyEmailResponse.AsObject> {
|
||||
const req = new GetMyEmailRequest();
|
||||
return this.grpcService.auth.getMyEmail(req, null).then((resp) => resp.toObject());
|
||||
|
@@ -182,7 +182,11 @@
|
||||
"STATE": "Status",
|
||||
"DELETE": "Benutzer löschen",
|
||||
"UNLOCK": "Benutzer entsperren",
|
||||
"LOCKEDDESCRIPTION": "Dieser Benutzer wurde aufgrund der Überschreitung der maximalen Anmeldeversuche gesperrt und muss zur erneuten Verwendung entsperrt werden."
|
||||
"LOCKEDDESCRIPTION": "Dieser Benutzer wurde aufgrund der Überschreitung der maximalen Anmeldeversuche gesperrt und muss zur erneuten Verwendung entsperrt werden.",
|
||||
"DELETEACCOUNT": "Account löschen",
|
||||
"DELETEACCOUNT_DESC": "Wenn du diese Aktion ausführst, wirst du abgemeldet und danach keinen Zugriff mehr auf dein Konto haben. Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"DELETEACCOUNT_BTN": "Account löschen",
|
||||
"DELETEACCOUNT_SUCCESS": "Account erfolgreich gelöscht!"
|
||||
},
|
||||
"DETAILS": {
|
||||
"DATECREATED": "Erstellt",
|
||||
@@ -190,7 +194,9 @@
|
||||
},
|
||||
"DIALOG": {
|
||||
"DELETE_TITLE": "User löschen",
|
||||
"DELETE_DESCRIPTION": "Sie sind im Begriff einen Benutzer endgültig zu löschen. Wollen Sie dies wirklich tun?"
|
||||
"DELETE_DESCRIPTION": "Sie sind im Begriff einen Benutzer endgültig zu löschen. Wollen Sie dies wirklich tun?",
|
||||
"DELETE_AUTH_DESCRIPTION": "Sie sind im Begriff Ihren Account endgültig zu löschen. Wollen Sie dies wirklich tun?",
|
||||
"DELETE_BTN": "Entgültig löschen"
|
||||
},
|
||||
"SENDEMAILDIALOG": {
|
||||
"TITLE": "Email Benachrichtigung senden",
|
||||
@@ -807,9 +813,9 @@
|
||||
},
|
||||
"PRIVATELABELING_POLICY": {
|
||||
"TITLE": "Private Labeling",
|
||||
"BTN":"Datei auswählen",
|
||||
"BTN": "Datei auswählen",
|
||||
"DESCRIPTION": "Definiere das Erscheinungsbild des Logins.",
|
||||
"ACTIVATEPREVIEW":"Preview aktivieren"
|
||||
"ACTIVATEPREVIEW": "Preview aktivieren"
|
||||
},
|
||||
"LOGIN_POLICY": {
|
||||
"TITLE": "Login Richtlinien",
|
||||
|
@@ -182,7 +182,11 @@
|
||||
"STATE": "Status",
|
||||
"DELETE": "Delete User",
|
||||
"UNLOCK": "Unlock User",
|
||||
"LOCKEDDESCRIPTION": "This user has been locked out due to exceeding the maximum login attempts and must be unlocked to be used again."
|
||||
"LOCKEDDESCRIPTION": "This user has been locked out due to exceeding the maximum login attempts and must be unlocked to be used again.",
|
||||
"DELETEACCOUNT": "Delete Account",
|
||||
"DELETEACCOUNT_DESC": "If you perform this action, you will be logged out and will no longer have access to your account. This action is not reversible, so please continue with caution.",
|
||||
"DELETEACCOUNT_BTN": "Delete Account",
|
||||
"DELETEACCOUNT_SUCCESS": "Account deleted successfully!"
|
||||
},
|
||||
"DETAILS": {
|
||||
"DATECREATED": "Created",
|
||||
@@ -190,7 +194,9 @@
|
||||
},
|
||||
"DIALOG": {
|
||||
"DELETE_TITLE": "Delete User",
|
||||
"DELETE_DESCRIPTION": "You are about to permanently delete a user. Are you sure?"
|
||||
"DELETE_DESCRIPTION": "You are about to permanently delete a user. Are you sure?",
|
||||
"DELETE_AUTH_DESCRIPTION": "You are about to permanently delete your personal account. Are you sure?",
|
||||
"DELETE_BTN": "Delete permanently"
|
||||
},
|
||||
"SENDEMAILDIALOG": {
|
||||
"TITLE": "Send Email Notification",
|
||||
|
@@ -182,7 +182,11 @@
|
||||
"STATE": "Stato",
|
||||
"DELETE": "Elimina utente",
|
||||
"UNLOCK": "Sblocca utente",
|
||||
"LOCKEDDESCRIPTION": "Questo utente \u00e8 stato bloccato a causa del superamento dei tentativi massimi di accesso e deve essere sbloccato per essere utilizzato di nuovo."
|
||||
"LOCKEDDESCRIPTION": "Questo utente \u00e8 stato bloccato a causa del superamento dei tentativi massimi di accesso e deve essere sbloccato per essere utilizzato di nuovo.",
|
||||
"DELETEACCOUNT": "Elimina account personale",
|
||||
"DELETEACCOUNT_DESC": "Se esegui questa azione, sarai disconnesso e non avrai più accesso al tuo account. Questa azione non può essere invertita.",
|
||||
"DELETEACCOUNT_BTN": "Elimina",
|
||||
"DELETEACCOUNT_SUCCESS": "Account eliminato con successo!"
|
||||
},
|
||||
"DETAILS": {
|
||||
"DATECREATED": "Creato",
|
||||
@@ -190,7 +194,9 @@
|
||||
},
|
||||
"DIALOG": {
|
||||
"DELETE_TITLE": "Elimina utente",
|
||||
"DELETE_DESCRIPTION": "Stai per eliminare definitivamente un utente. Sei sicuro?"
|
||||
"DELETE_DESCRIPTION": "Stai per eliminare definitivamente un utente. Sei sicuro?",
|
||||
"DELETE_AUTH_DESCRIPTION": "Stai per eleminare il tuo account personale in modo permanente. Vuoi continuare?",
|
||||
"DELETE_BTN": "Elimina"
|
||||
},
|
||||
"SENDEMAILDIALOG": {
|
||||
"TITLE": "Invia una notifica via e-mail",
|
||||
|
Reference in New Issue
Block a user