mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:27:42 +00:00
feat: add domain verification notification (#649)
* fix: dont (re)generate client secret with auth type none * fix(cors): allow Origin from request * feat: add origin allow list and fix some core issues * rename migration * fix UserIDsByDomain * feat: send email to users after domain claim * username * check origin on userinfo * update oidc pkg * fix: add migration 1.6 * change username * change username * remove unique email aggregate * change username in mgmt * search global user by login name * fix test * change user search in angular * fix tests * merge * userview in angular * fix merge * Update pkg/grpc/management/proto/management.proto Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * Update internal/notification/static/i18n/de.yaml Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * fix Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
2715
console/package-lock.json
generated
2715
console/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { ProjectGrantView, ProjectRole, ProjectView, User } from 'src/app/proto/generated/management_pb';
|
||||
import { ProjectGrantView, ProjectRole, ProjectView, UserView } from 'src/app/proto/generated/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ProjectService } from 'src/app/services/project.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
@@ -21,7 +21,7 @@ export enum CreationType {
|
||||
export class MemberCreateDialogComponent {
|
||||
private projectId: string = '';
|
||||
private grantId: string = '';
|
||||
public preselectedUsers: Array<User.AsObject> = [];
|
||||
public preselectedUsers: Array<UserView.AsObject> = [];
|
||||
|
||||
|
||||
public creationType!: CreationType;
|
||||
@@ -31,7 +31,7 @@ export class MemberCreateDialogComponent {
|
||||
CreationType.PROJECT_OWNED,
|
||||
CreationType.PROJECT_GRANTED,
|
||||
];
|
||||
public users: Array<User.AsObject> = [];
|
||||
public users: Array<UserView.AsObject> = [];
|
||||
public roles: Array<ProjectRole.AsObject> | string[] = [];
|
||||
public CreationType: any = CreationType;
|
||||
public ProjectAutocompleteType: any = ProjectAutocompleteType;
|
||||
|
@@ -6,7 +6,7 @@ import { MatSelectChange } from '@angular/material/select';
|
||||
import { MatTable } from '@angular/material/table';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { ProjectGrantView, ProjectMember, ProjectType, ProjectView, User } from 'src/app/proto/generated/management_pb';
|
||||
import { ProjectGrantView, ProjectMember, ProjectType, ProjectView, UserView } from 'src/app/proto/generated/management_pb';
|
||||
import { ProjectService } from 'src/app/services/project.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@@ -128,7 +128,7 @@ export class ProjectMembersComponent {
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
const users: User.AsObject[] = resp.users;
|
||||
const users: UserView.AsObject[] = resp.users;
|
||||
const roles: string[] = resp.roles;
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
|
@@ -1,17 +1,17 @@
|
||||
<form>
|
||||
<mat-form-field *ngIf="target == UserTarget.SELF" appearance="outline" class="full-width">
|
||||
<mat-label>Organizations User Email</mat-label>
|
||||
<mat-label>Organizations User Loginname</mat-label>
|
||||
|
||||
<input matInput *ngIf="singleOutput" type="text" placeholder="Search for the user email" #usernameInput
|
||||
<input matInput *ngIf="singleOutput" type="text" placeholder="Search for the user loginname" #usernameInput
|
||||
[formControl]="myControl" [matAutocomplete]="auto" />
|
||||
|
||||
<mat-chip-list *ngIf="!singleOutput" #chipList aria-label="useremail selection">
|
||||
<mat-chip-list *ngIf="!singleOutput" #chipList aria-label="loginname selection">
|
||||
<mat-chip class="chip" *ngFor="let selecteduser of users" [selectable]="selectable" [removable]="removable"
|
||||
(removed)="remove(selecteduser)">
|
||||
{{ selecteduser?.firstName }} {{selecteduser.lastName}} | <small> {{selecteduser.email}}</small>
|
||||
{{ selecteduser?.firstName }} {{selecteduser.lastName}} | <small> {{selecteduser.preferredLoginName}}</small>
|
||||
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input placeholder="{{'ORG_DETAIL.MEMBER.EMAIL' | translate}}" #usernameInput [formControl]="myControl"
|
||||
<input placeholder="{{'ORG_DETAIL.MEMBER.LOGINNAME' | translate}}" #usernameInput [formControl]="myControl"
|
||||
[matAutocomplete]="auto" [matChipInputFor]="chipList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
|
||||
(matChipInputTokenEnd)="add($event)" />
|
||||
@@ -23,15 +23,15 @@
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let user of filteredUsers" [value]="user">
|
||||
{{user.firstName}} {{user.lastName}}
|
||||
<small>{{user.email}}</small>
|
||||
<small>{{user.preferredLoginName}}</small>
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
|
||||
<div *ngIf="target == UserTarget.EXTERNAL" class="line">
|
||||
<mat-form-field class="form-field" appearance="outline">
|
||||
<mat-label>Global User Email</mat-label>
|
||||
<input matInput type="text" [formControl]="globalEmailControl" />
|
||||
<mat-label>Global User Loginname</mat-label>
|
||||
<input matInput type="text" [formControl]="globalLoginNameControl" />
|
||||
</mat-form-field>
|
||||
|
||||
<button color="primary" mat-icon-button (click)="getGlobalUser()">
|
||||
@@ -42,7 +42,7 @@
|
||||
<div *ngIf="target == UserTarget.EXTERNAL && users.length > 0">
|
||||
<span class="found-label">{{'USER.SEARCH.FOUND' | translate}}:</span>
|
||||
<div class="found-user-row" *ngFor="let user of users; index as i">
|
||||
<span>{{user.email}}</span>
|
||||
<span>{{user.preferredLoginName}}</span>
|
||||
<button mat-icon-button>
|
||||
<i class="las la-minus-circle" (click)="users.splice(i, 1)"></i>
|
||||
</button>
|
||||
@@ -52,4 +52,4 @@
|
||||
<p class="target-desc">{{(target == UserTarget.SELF ? 'USER.TARGET.SELF' : 'USER.TARGET.EXTERNAL') | translate}}
|
||||
<a (click)="changeTarget()">{{'USER.TARGET.CLICKHERE' | translate}}</a>
|
||||
</p>
|
||||
</form>
|
||||
</form>
|
||||
|
@@ -5,7 +5,7 @@ import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material
|
||||
import { MatChipInputEvent } from '@angular/material/chips';
|
||||
import { from, of, Subject } from 'rxjs';
|
||||
import { debounceTime, switchMap, takeUntil, tap } from 'rxjs/operators';
|
||||
import { SearchMethod, User, UserSearchKey, UserSearchQuery } from 'src/app/proto/generated/management_pb';
|
||||
import { SearchMethod, UserView, UserSearchKey, UserSearchQuery } from 'src/app/proto/generated/management_pb';
|
||||
import { MgmtUserService } from 'src/app/services/mgmt-user.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@@ -26,18 +26,18 @@ export class SearchUserAutocompleteComponent {
|
||||
public separatorKeysCodes: number[] = [ENTER, COMMA];
|
||||
|
||||
public myControl: FormControl = new FormControl();
|
||||
public globalEmailControl: FormControl = new FormControl();
|
||||
public globalLoginNameControl: FormControl = new FormControl();
|
||||
|
||||
public emails: string[] = [];
|
||||
@Input() public users: Array<User.AsObject> = [];
|
||||
public filteredUsers: Array<User.AsObject> = [];
|
||||
public loginNames: string[] = [];
|
||||
@Input() public users: Array<UserView.AsObject> = [];
|
||||
public filteredUsers: Array<UserView.AsObject> = [];
|
||||
public isLoading: boolean = false;
|
||||
public target: UserTarget = UserTarget.SELF;
|
||||
public hint: string = '';
|
||||
public UserTarget: any = UserTarget;
|
||||
@ViewChild('usernameInput') public usernameInput!: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('auto') public matAutocomplete!: MatAutocomplete;
|
||||
@Output() public selectionChanged: EventEmitter<User.AsObject | User.AsObject[]> = new EventEmitter();
|
||||
@Output() public selectionChanged: EventEmitter<UserView.AsObject | UserView.AsObject[]> = new EventEmitter();
|
||||
@Input() public singleOutput: boolean = false;
|
||||
|
||||
private unsubscribed$: Subject<void> = new Subject();
|
||||
@@ -51,7 +51,7 @@ export class SearchUserAutocompleteComponent {
|
||||
tap(() => this.isLoading = true),
|
||||
switchMap(value => {
|
||||
const query = new UserSearchQuery();
|
||||
query.setKey(UserSearchKey.USERSEARCHKEY_EMAIL);
|
||||
query.setKey(UserSearchKey.USERSEARCHKEY_USER_NAME);
|
||||
query.setValue(value);
|
||||
query.setMethod(SearchMethod.SEARCHMETHOD_CONTAINS_IGNORE_CASE);
|
||||
if (this.target === UserTarget.SELF) {
|
||||
@@ -68,8 +68,8 @@ export class SearchUserAutocompleteComponent {
|
||||
});
|
||||
}
|
||||
|
||||
public displayFn(user?: User.AsObject): string | undefined {
|
||||
return user ? `${user.email}` : undefined;
|
||||
public displayFn(user?: UserView.AsObject): string | undefined {
|
||||
return user ? `${user.preferredLoginName}` : undefined;
|
||||
}
|
||||
|
||||
public add(event: MatChipInputEvent): void {
|
||||
@@ -79,8 +79,8 @@ export class SearchUserAutocompleteComponent {
|
||||
|
||||
if ((value || '').trim()) {
|
||||
const index = this.filteredUsers.findIndex((user) => {
|
||||
if (user.email) {
|
||||
return user.email === value;
|
||||
if (user.preferredLoginName) {
|
||||
return user.preferredLoginName === value;
|
||||
}
|
||||
});
|
||||
if (index > -1) {
|
||||
@@ -98,7 +98,7 @@ export class SearchUserAutocompleteComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public remove(user: User.AsObject): void {
|
||||
public remove(user: UserView.AsObject): void {
|
||||
const index = this.users.indexOf(user);
|
||||
|
||||
if (index >= 0) {
|
||||
@@ -138,7 +138,7 @@ export class SearchUserAutocompleteComponent {
|
||||
}
|
||||
|
||||
public getGlobalUser(): void {
|
||||
this.userService.GetUserByEmailGlobal(this.globalEmailControl.value).then(user => {
|
||||
this.userService.GetUserByLoginNameGlobal(this.globalLoginNameControl.value).then(user => {
|
||||
this.users = [user.toObject()];
|
||||
this.selectionChanged.emit(this.users);
|
||||
}).catch(error => {
|
||||
|
@@ -22,7 +22,7 @@ import {
|
||||
ProjectState,
|
||||
ProjectType,
|
||||
ProjectView,
|
||||
User,
|
||||
UserView,
|
||||
UserGrantSearchKey,
|
||||
} from 'src/app/proto/generated/management_pb';
|
||||
import { OrgService } from 'src/app/services/org.service';
|
||||
@@ -216,7 +216,7 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
const users: User.AsObject[] = resp.users;
|
||||
const users: UserView.AsObject[] = resp.users;
|
||||
const roles: string[] = resp.roles;
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
|
@@ -3,7 +3,7 @@ import { Component, Input, OnInit } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Router } from '@angular/router';
|
||||
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
||||
import { MemberType, User, UserMembershipSearchResponse } from 'src/app/proto/generated/management_pb';
|
||||
import { MemberType, UserView, UserMembershipSearchResponse } from 'src/app/proto/generated/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { MgmtUserService } from 'src/app/services/mgmt-user.service';
|
||||
import { OrgService } from 'src/app/services/org.service';
|
||||
@@ -35,7 +35,7 @@ export class MembershipsComponent implements OnInit {
|
||||
public loading: boolean = false;
|
||||
public memberships!: UserMembershipSearchResponse.AsObject;
|
||||
|
||||
@Input() public user!: User.AsObject;
|
||||
@Input() public user!: UserView.AsObject;
|
||||
public MemberType: any = MemberType;
|
||||
|
||||
constructor(
|
||||
@@ -92,7 +92,7 @@ export class MembershipsComponent implements OnInit {
|
||||
}
|
||||
|
||||
public createIamMember(response: any): void {
|
||||
const users: User.AsObject[] = response.users;
|
||||
const users: UserView.AsObject[] = response.users;
|
||||
const roles: string[] = response.roles;
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
@@ -107,7 +107,7 @@ export class MembershipsComponent implements OnInit {
|
||||
}
|
||||
|
||||
private createOrgMember(response: any): void {
|
||||
const users: User.AsObject[] = response.users;
|
||||
const users: UserView.AsObject[] = response.users;
|
||||
const roles: string[] = response.roles;
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
@@ -122,7 +122,7 @@ export class MembershipsComponent implements OnInit {
|
||||
}
|
||||
|
||||
private createGrantedProjectMember(response: any): void {
|
||||
const users: User.AsObject[] = response.users;
|
||||
const users: UserView.AsObject[] = response.users;
|
||||
const roles: string[] = response.roles;
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
@@ -142,7 +142,7 @@ export class MembershipsComponent implements OnInit {
|
||||
}
|
||||
|
||||
private createOwnedProjectMember(response: any): void {
|
||||
const users: User.AsObject[] = response.users;
|
||||
const users: UserView.AsObject[] = response.users;
|
||||
const roles: string[] = response.roles;
|
||||
|
||||
if (users && users.length && roles && roles.length) {
|
||||
|
@@ -7,7 +7,7 @@ import {
|
||||
ChangeRequest,
|
||||
Changes,
|
||||
CreateUserRequest,
|
||||
Email,
|
||||
LoginName,
|
||||
Gender,
|
||||
MultiFactors,
|
||||
NotificationType,
|
||||
@@ -391,11 +391,11 @@ export class MgmtUserService {
|
||||
);
|
||||
}
|
||||
|
||||
public async GetUserByEmailGlobal(email: string): Promise<User> {
|
||||
const req = new Email();
|
||||
req.setEmail(email);
|
||||
public async GetUserByLoginNameGlobal(loginName: string): Promise<UserView> {
|
||||
const req = new LoginName();
|
||||
req.setLoginName(loginName);
|
||||
return await this.request(
|
||||
c => c.getUserByEmailGlobal,
|
||||
c => c.getUserByLoginNameGlobal,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
|
Reference in New Issue
Block a user