summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts305
1 files changed, 305 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts
new file mode 100644
index 000000000..1a0ddf35c
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts
@@ -0,0 +1,305 @@
+import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { Validators } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+
+import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import _ from 'lodash';
+import moment from 'moment';
+import { forkJoin as observableForkJoin } from 'rxjs';
+
+import { AuthService } from '~/app/shared/api/auth.service';
+import { RoleService } from '~/app/shared/api/role.service';
+import { SettingsService } from '~/app/shared/api/settings.service';
+import { UserService } from '~/app/shared/api/user.service';
+import { ConfirmationModalComponent } from '~/app/shared/components/confirmation-modal/confirmation-modal.component';
+import { SelectMessages } from '~/app/shared/components/select/select-messages.model';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
+import { Icons } from '~/app/shared/enum/icons.enum';
+import { NotificationType } from '~/app/shared/enum/notification-type.enum';
+import { CdForm } from '~/app/shared/forms/cd-form';
+import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
+import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
+import { CdValidators } from '~/app/shared/forms/cd-validators';
+import { CdPwdExpirationSettings } from '~/app/shared/models/cd-pwd-expiration-settings';
+import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
+import { ModalService } from '~/app/shared/services/modal.service';
+import { NotificationService } from '~/app/shared/services/notification.service';
+import { PasswordPolicyService } from '~/app/shared/services/password-policy.service';
+import { UserFormMode } from './user-form-mode.enum';
+import { UserFormRoleModel } from './user-form-role.model';
+import { UserFormModel } from './user-form.model';
+
+@Component({
+ selector: 'cd-user-form',
+ templateUrl: './user-form.component.html',
+ styleUrls: ['./user-form.component.scss']
+})
+export class UserFormComponent extends CdForm implements OnInit {
+ @ViewChild('removeSelfUserReadUpdatePermissionTpl', { static: true })
+ removeSelfUserReadUpdatePermissionTpl: TemplateRef<any>;
+
+ modalRef: NgbModalRef;
+
+ userForm: CdFormGroup;
+ response: UserFormModel;
+
+ userFormMode = UserFormMode;
+ mode: UserFormMode;
+ allRoles: Array<UserFormRoleModel>;
+ messages = new SelectMessages({ empty: $localize`There are no roles.` });
+ action: string;
+ resource: string;
+ passwordPolicyHelpText = '';
+ passwordStrengthLevelClass: string;
+ passwordValuation: string;
+ icons = Icons;
+ pwdExpirationSettings: CdPwdExpirationSettings;
+ pwdExpirationFormat = 'YYYY-MM-DD';
+
+ constructor(
+ private authService: AuthService,
+ private authStorageService: AuthStorageService,
+ private route: ActivatedRoute,
+ public router: Router,
+ private modalService: ModalService,
+ private roleService: RoleService,
+ private userService: UserService,
+ private notificationService: NotificationService,
+ public actionLabels: ActionLabelsI18n,
+ private passwordPolicyService: PasswordPolicyService,
+ private formBuilder: CdFormBuilder,
+ private settingsService: SettingsService
+ ) {
+ super();
+ this.resource = $localize`user`;
+ this.createForm();
+ this.messages = new SelectMessages({ empty: $localize`There are no roles.` });
+ }
+
+ createForm() {
+ this.passwordPolicyService.getHelpText().subscribe((helpText: string) => {
+ this.passwordPolicyHelpText = helpText;
+ });
+ this.userForm = this.formBuilder.group(
+ {
+ username: [
+ '',
+ [Validators.required],
+ [CdValidators.unique(this.userService.validateUserName, this.userService)]
+ ],
+ name: [''],
+ password: [
+ '',
+ [],
+ [
+ CdValidators.passwordPolicy(
+ this.userService,
+ () => this.userForm.getValue('username'),
+ (_valid: boolean, credits: number, valuation: string) => {
+ this.passwordStrengthLevelClass = this.passwordPolicyService.mapCreditsToCssClass(
+ credits
+ );
+ this.passwordValuation = _.defaultTo(valuation, '');
+ }
+ )
+ ]
+ ],
+ confirmpassword: [''],
+ pwdExpirationDate: [undefined],
+ email: ['', [CdValidators.email]],
+ roles: [[]],
+ enabled: [true, [Validators.required]],
+ pwdUpdateRequired: [true]
+ },
+ {
+ validators: [CdValidators.match('password', 'confirmpassword')]
+ }
+ );
+ }
+
+ ngOnInit() {
+ if (this.router.url.startsWith('/user-management/users/edit')) {
+ this.mode = this.userFormMode.editing;
+ this.action = this.actionLabels.EDIT;
+ } else {
+ this.action = this.actionLabels.CREATE;
+ }
+
+ const observables = [this.roleService.list(), this.settingsService.getStandardSettings()];
+ observableForkJoin(observables).subscribe(
+ (result: [UserFormRoleModel[], CdPwdExpirationSettings]) => {
+ this.allRoles = _.map(result[0], (role) => {
+ role.enabled = true;
+ return role;
+ });
+ this.pwdExpirationSettings = new CdPwdExpirationSettings(result[1]);
+
+ if (this.mode === this.userFormMode.editing) {
+ this.initEdit();
+ } else {
+ if (this.pwdExpirationSettings.pwdExpirationSpan > 0) {
+ const pwdExpirationDateField = this.userForm.get('pwdExpirationDate');
+ const expirationDate = moment();
+ expirationDate.add(this.pwdExpirationSettings.pwdExpirationSpan, 'day');
+ pwdExpirationDateField.setValue(expirationDate.format(this.pwdExpirationFormat));
+ pwdExpirationDateField.setValidators([Validators.required]);
+ }
+
+ this.loadingReady();
+ }
+ }
+ );
+ }
+
+ initEdit() {
+ this.disableForEdit();
+ this.route.params.subscribe((params: { username: string }) => {
+ const username = params.username;
+ this.userService.get(username).subscribe((userFormModel: UserFormModel) => {
+ this.response = _.cloneDeep(userFormModel);
+ this.setResponse(userFormModel);
+
+ this.loadingReady();
+ });
+ });
+ }
+
+ disableForEdit() {
+ this.userForm.get('username').disable();
+ }
+
+ setResponse(response: UserFormModel) {
+ ['username', 'name', 'email', 'roles', 'enabled', 'pwdUpdateRequired'].forEach((key) =>
+ this.userForm.get(key).setValue(response[key])
+ );
+ const expirationDate = response['pwdExpirationDate'];
+ if (expirationDate) {
+ this.userForm
+ .get('pwdExpirationDate')
+ .setValue(moment(expirationDate * 1000).format(this.pwdExpirationFormat));
+ }
+ }
+
+ getRequest(): UserFormModel {
+ const userFormModel = new UserFormModel();
+ ['username', 'password', 'name', 'email', 'roles', 'enabled', 'pwdUpdateRequired'].forEach(
+ (key) => (userFormModel[key] = this.userForm.get(key).value)
+ );
+ const expirationDate = this.userForm.get('pwdExpirationDate').value;
+ if (expirationDate) {
+ const mom = moment(expirationDate, this.pwdExpirationFormat);
+ if (
+ this.mode !== this.userFormMode.editing ||
+ this.response.pwdExpirationDate !== mom.unix()
+ ) {
+ mom.set({ hour: 23, minute: 59, second: 59 });
+ }
+ userFormModel['pwdExpirationDate'] = mom.unix();
+ }
+ return userFormModel;
+ }
+
+ createAction() {
+ const userFormModel = this.getRequest();
+ this.userService.create(userFormModel).subscribe(
+ () => {
+ this.notificationService.show(
+ NotificationType.success,
+ $localize`Created user '${userFormModel.username}'`
+ );
+ this.router.navigate(['/user-management/users']);
+ },
+ () => {
+ this.userForm.setErrors({ cdSubmitButton: true });
+ }
+ );
+ }
+
+ editAction() {
+ if (this.isUserRemovingNeededRolePermissions()) {
+ const initialState = {
+ titleText: $localize`Update user`,
+ buttonText: $localize`Continue`,
+ bodyTpl: this.removeSelfUserReadUpdatePermissionTpl,
+ onSubmit: () => {
+ this.modalRef.close();
+ this.doEditAction();
+ },
+ onCancel: () => {
+ this.userForm.setErrors({ cdSubmitButton: true });
+ this.userForm.get('roles').reset(this.userForm.get('roles').value);
+ }
+ };
+ this.modalRef = this.modalService.show(ConfirmationModalComponent, initialState);
+ } else {
+ this.doEditAction();
+ }
+ }
+
+ public isCurrentUser(): boolean {
+ return this.authStorageService.getUsername() === this.userForm.getValue('username');
+ }
+
+ private isUserChangingRoles(): boolean {
+ const isCurrentUser = this.isCurrentUser();
+ return (
+ isCurrentUser &&
+ this.response &&
+ !_.isEqual(this.response.roles, this.userForm.getValue('roles'))
+ );
+ }
+
+ private isUserRemovingNeededRolePermissions(): boolean {
+ const isCurrentUser = this.isCurrentUser();
+ return isCurrentUser && !this.hasUserReadUpdatePermissions(this.userForm.getValue('roles'));
+ }
+
+ private hasUserReadUpdatePermissions(roles: Array<string> = []) {
+ for (const role of this.allRoles) {
+ if (roles.indexOf(role.name) !== -1 && role.scopes_permissions['user']) {
+ const userPermissions = role.scopes_permissions['user'];
+ return ['read', 'update'].every((permission) => {
+ return userPermissions.indexOf(permission) !== -1;
+ });
+ }
+ }
+ return false;
+ }
+
+ private doEditAction() {
+ const userFormModel = this.getRequest();
+ this.userService.update(userFormModel).subscribe(
+ () => {
+ if (this.isUserChangingRoles()) {
+ this.authService.logout(() => {
+ this.notificationService.show(
+ NotificationType.info,
+ $localize`You were automatically logged out because your roles have been changed.`
+ );
+ });
+ } else {
+ this.notificationService.show(
+ NotificationType.success,
+ $localize`Updated user '${userFormModel.username}'`
+ );
+ this.router.navigate(['/user-management/users']);
+ }
+ },
+ () => {
+ this.userForm.setErrors({ cdSubmitButton: true });
+ }
+ );
+ }
+
+ clearExpirationDate() {
+ this.userForm.get('pwdExpirationDate').setValue(undefined);
+ }
+
+ submit() {
+ if (this.mode === this.userFormMode.editing) {
+ this.editAction();
+ } else {
+ this.createAction();
+ }
+ }
+}