Merge pull request #5056 from pengpengshui/leftNav

Add function about admin reset user's password
This commit is contained in:
Qian Deng 2018-05-30 22:35:36 -04:00 committed by GitHub
commit b461e98fde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 239 additions and 5 deletions

View File

@ -0,0 +1,49 @@
<clr-modal [(clrModalOpen)]="opened" [clrModalStaticBackdrop]="true" [clrModalClosable]="false">
<h3 class="modal-title">{{'RESET_PWD.TITLE' | translate}}</h3>
<inline-alert class="modal-title" (confirmEvt)="confirmCancel($event)"></inline-alert>
<div class="modal-body" style="overflow-y: hidden;">
<form #resetPwdForm="ngForm" class="form">
<section class="form-block">
<div class="form-group">
<label for="newPassword" class="form-group-label-override">{{'CHANGE_PWD.NEW_PWD' | translate}}</label>
<label for="newPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" [class.invalid]='!getValidationState("newPassword")'>
<input type="password" id="newPassword" placeholder='{{"PLACEHOLDER.NEW_PWD" | translate}}'
required
pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,20}$"
name="newPassword"
[(ngModel)]="password"
#newPassInput="ngModel"
size="25"
(input)='handleValidation("newPassword", false)'
(blur)='handleValidation("newPassword", true)'>
<span class="tooltip-content">
{{'TOOLTIP.PASSWORD' | translate}}
</span>
</label>
</div>
<div class="form-group">
<label for="reNewPassword" class="form-group-label-override">{{'CHANGE_PWD.CONFIRM_PWD' | translate}}</label>
<label for="reNewPassword" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-md tooltip-top-left" [class.invalid]='!getValidationState("reNewPassword")'>
<input type="password" id="reNewPassword" placeholder='{{"PLACEHOLDER.CONFIRM_PWD" | translate}}'
required
pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,20}$"
name="reNewPassword"
[(ngModel)]="confirmPwd"
#reNewPassInput
size="25"
(input)='handleValidation("reNewPassword", false)'
(blur)='handleValidation("reNewPassword", true)'>
<span class="tooltip-content">
{{'TOOLTIP.CONFIRM_PWD' | translate}}
</span>
</label>
</div>
</section>
</form>
</div>
<div class="modal-footer">
<span class="spinner spinner-inline" style="top:8px;" [hidden]="showProgress === false"></span>
<button type="button" class="btn btn-outline" (click)="close()">{{'BUTTON.CANCEL' | translate}}</button>
<button type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="send()">{{'BUTTON.OK' | translate}}</button>
</div>
</clr-modal>

View File

@ -0,0 +1,3 @@
.form .form-block, form .form-block {
margin: .5rem 0 2rem 0;
}

View File

@ -0,0 +1,149 @@
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {Component, ViewChild, ChangeDetectorRef} from '@angular/core';
import { NgForm } from '@angular/forms';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
import {UserService} from "../user.service";
@Component({
selector: 'change-password',
templateUrl: "change-password.component.html",
styleUrls: ['./change-password.component.scss']
})
export class ChangePasswordComponent {
opened: boolean = false;
onGoing: boolean = false;
password: string = "";
private validationState: any = {
"newPassword": true,
"reNewPassword": true
};
confirmPwd: string = "";
userId: number;
@ViewChild("resetPwdForm") resetPwdForm: NgForm;
@ViewChild(InlineAlertComponent)
inlineAlert: InlineAlertComponent;
constructor(
private userService: UserService,
private msgHandler: MessageHandlerService,
private ref: ChangeDetectorRef) { }
public get showProgress(): boolean {
return this.onGoing;
}
public get isValid(): boolean {
return this.resetPwdForm && this.resetPwdForm.valid && this.samePassword();
}
public getValidationState(key: string): boolean {
return this.validationState &&
this.validationState[key];
}
confirmCancel(event: boolean): void {
this.opened = false;
}
public open(userId: number): void {
this.onGoing = false;
this.validationState = {
"newPassword": true,
"reNewPassword": true
};
this.resetPwdForm.resetForm();
this.inlineAlert.close();
this.userId = userId;
this.opened = true;
}
public close(): void {
if (this.password || this.confirmPwd) {
// Need user confirmation
this.inlineAlert.showInlineConfirmation({
message: "ALERT.FORM_CHANGE_CONFIRMATION"
});
}else {
this.opened = false;
}
}
public send(): void {
// Double confirm to avoid improper situations
if (!this.password || !this.confirmPwd) {
return;
}
if (!this.isValid) {
return;
}
this.onGoing = true;
this.userService.changePassword(this.userId, this.password, this.confirmPwd)
.then(() => {
this.onGoing = false;
this.opened = false;
this.msgHandler.showSuccess("USER.RESET_Ok");
let hnd = setInterval(() => this.ref.markForCheck(), 100);
setTimeout(() => clearInterval(hnd), 2000);
})
.catch(error => {
this.onGoing = false;
if (this.msgHandler.isAppLevel(error)) {
this.msgHandler.handleError(error);
this.opened = false;
} else {
this.inlineAlert.showInlineError(error);
}
});
}
public handleValidation(key: string, flag: boolean): void {
if (!flag) {
this.validationState[key] = true;
} else {
this.validationState[key] = this.getControlValidationState(key);
if (this.validationState[key]) {
this.validationState["reNewPassword"] = this.samePassword();
}
}
}
getControlValidationState(key: string): boolean {
if (this.resetPwdForm) {
let control = this.resetPwdForm.controls[key];
if (control) {
return control.valid;
}
}
return false;
}
samePassword(): boolean {
if (this.resetPwdForm) {
let control1 = this.resetPwdForm.controls["newPassword"];
let control2 = this.resetPwdForm.controls["reNewPassword"];
if (control1 && control2) {
return control1.value === control2.value;
}
}
return false;
}
}

View File

@ -13,6 +13,7 @@
<clr-dg-action-bar>
<button type="button" class="btn btn-sm btn-secondary" (click)="addNewUser()" [disabled]="!canCreateUser"><clr-icon shape="plus" size="16"></clr-icon>&nbsp;{{'USER.ADD_ACTION' | translate}}</button>
<button type="button" class="btn btn-sm btn-secondary" id="set-admin" [disabled]="!ifSameRole" (click)="changeAdminRole()" ><clr-icon shape="wrench" size="16"></clr-icon>&nbsp;{{ISADMNISTRATOR | translate}}</button>
<button type="button" class="btn btn-sm btn-secondary" id="changePwd" [disabled]="!(selectedRow.length==1)" (click)="openChangePwdModal()" ><clr-icon shape="edit" size="16"></clr-icon>&nbsp;{{'RESET_PWD.TITLE' | translate | uppercase}}</button>
<button type="button" class="btn btn-sm btn-secondary" (click)="deleteUsers(selectedRow)" [disabled]="!selectedRow.length || onlySelf || !canCreateUser"><clr-icon shape="times" size="16"></clr-icon>&nbsp;{{'USER.DEL_ACTION' | translate}}</button>
</clr-dg-action-bar>
<clr-dg-column>{{'USER.COLUMN_NAME' | translate}}</clr-dg-column>
@ -34,5 +35,6 @@
</clr-datagrid>
</div>
<new-user-modal (addNew)="addUserToList($event)"></new-user-modal>
<change-password></change-password>
</div>
</div>
</div>

View File

@ -26,6 +26,7 @@ import { AppConfigService } from '../app-config.service';
import { NewUserModalComponent } from './new-user-modal.component';
import { UserService } from './user.service';
import { User } from './user';
import {ChangePasswordComponent} from "./change-password/change-password.component";
import {operateChanges, OperateInfo, OperationService, OperationState} from "harbor-ui";
/**
* NOTES:
@ -62,6 +63,8 @@ export class UserComponent implements OnInit, OnDestroy {
private deletionSubscription: Subscription;
@ViewChild(NewUserModalComponent)
newUserDialog: NewUserModalComponent;
@ViewChild(ChangePasswordComponent)
changePwdDialog: ChangePasswordComponent;
constructor(
private userService: UserService,
@ -163,6 +166,13 @@ export class UserComponent implements OnInit, OnDestroy {
}
}
openChangePwdModal(): void {
if (this.selectedRow.length === 1) {
this.changePwdDialog.open(this.selectedRow[0].user_id);
}
}
// Filter items by keywords
doFilter(terms: string): void {
this.selectedRow = [];

View File

@ -16,6 +16,7 @@ import { SharedModule } from '../shared/shared.module';
import { UserComponent } from './user.component';
import { NewUserModalComponent } from './new-user-modal.component';
import { UserService } from './user.service';
import {ChangePasswordComponent} from "./change-password/change-password.component";
@NgModule({
imports: [
@ -23,6 +24,7 @@ import { UserService } from './user.service';
],
declarations: [
UserComponent,
ChangePasswordComponent,
NewUserModalComponent
],
exports: [

View File

@ -73,4 +73,19 @@ export class UserService {
.then(() => null)
.catch(error => this.handleError(error));
}
// admin change normal user pwd
changePassword(uid: number, newPassword: string, confirmPwd: string): Promise<any> {
if (!uid || !newPassword) {
return Promise.reject("Invalid change uid or password");
}
return this.http.put(userMgmtEndpoint + '/' + uid + '/password',
{"old_password": newPassword, 'new_password': confirmPwd}, HTTP_JSON_OPTIONS)
.toPromise()
.then(response => response)
.catch(error => {
return Promise.reject(error);
});
}
}

View File

@ -135,7 +135,8 @@
"DELETION_SUMMARY": "Do you want to delete user {{param}}?",
"DELETE_SUCCESS": "Users deleted successfully.",
"ITEMS": "items",
"OF": "of"
"OF": "of",
"RESET_Ok": "Users password reset successfully"
},
"PROJECT": {
"PROJECTS": "Projects",

View File

@ -135,7 +135,8 @@
"DELETION_SUMMARY": "¿Quiere eliminar el usuario {{param}}?",
"DELETE_SUCCESS": "Usuario eliminado satisfactoriamente.",
"ITEMS": "elementos",
"OF": "of"
"OF": "of",
"RESET_Ok": "Users password reset successfully"
},
"PROJECT": {
"PROJECTS": "Proyectos",

View File

@ -118,7 +118,8 @@
"DELETION_SUMMARY": "Voules-vous supprimer l'utilisateur {{param}}?",
"DELETE_SUCCESS": "Utilisateur supprimé avec succès.",
"ITEMS": "items",
"OF": "de"
"OF": "de",
"RESET_Ok": "Users password reset successfully"
},
"PROJECT": {
"PROJECTS": "Projets",

View File

@ -135,7 +135,8 @@
"DELETION_SUMMARY": "你确认删除用户 {{param}}?",
"DELETE_SUCCESS": "成功删除用户。",
"OF": "共计",
"ITEMS": "条记录"
"ITEMS": "条记录",
"RESET_Ok": "成功修改用户密码"
},
"PROJECT": {
"PROJECTS": "项目",