diff options
author | Martin Stockhammer <martin_s@apache.org> | 2020-11-11 21:01:46 +0100 |
---|---|---|
committer | Martin Stockhammer <martin_s@apache.org> | 2020-11-11 21:01:46 +0100 |
commit | 055964cce1d8c3b272227520836cd494048ab3e4 (patch) | |
tree | 6f1f3e13837c929fa13ec160628a6ba490c6411d /archiva-modules/archiva-web/archiva-webapp/src | |
parent | 1caa397790ee006b645e6ca9f666382ff0a2f97f (diff) | |
download | archiva-055964cce1d8c3b272227520836cd494048ab3e4.tar.gz archiva-055964cce1d8c3b272227520836cd494048ab3e4.zip |
Updating user add component
Diffstat (limited to 'archiva-modules/archiva-web/archiva-webapp/src')
10 files changed, 258 insertions, 56 deletions
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/error-result.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/error-result.ts index 64e97659f..b54fa848f 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/error-result.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/error-result.ts @@ -20,6 +20,7 @@ import {ErrorMessage} from "./error-message"; export class ErrorResult { error_messages: Array<ErrorMessage> + status: number; constructor(errorMessages: Array<ErrorMessage>) { this.error_messages = errorMessages; diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/user.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/user.spec.ts new file mode 100644 index 000000000..40e143798 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/user.spec.ts @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { User } from './user'; + +describe('User', () => { + it('should create an instance', () => { + expect(new User()).toBeTruthy(); + }); +}); diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/user.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/user.ts new file mode 100644 index 000000000..f264d0218 --- /dev/null +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/user.ts @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { UserInfo } from './user-info'; + +export class User extends UserInfo { + password: string; + confirm_password: string; +} diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/manage-users/manage-users.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/manage-users/manage-users.component.html index c61718009..08b3fca81 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/manage-users/manage-users.component.html +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/manage-users/manage-users.component.html @@ -24,6 +24,9 @@ <li class="nav-item"> <a class="nav-link" routerLink="/user/users/add" routerLinkActive="active" href="#">{{'users.add.head' |translate }}</a> </li> + <li class="nav-item"> + <a class="nav-link" routerLink="/user/users/edit/guest" routerLinkActive="active" href="#">{{'users.edit.head' |translate }}</a> + </li> </ul> <router-outlet ></router-outlet>
\ No newline at end of file diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.html index 1bfac6606..ad538a838 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.html +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.html @@ -18,47 +18,67 @@ --> <form class="mt-3 mb-3" [formGroup]="userForm" (ngSubmit)="onSubmit()"> - <fieldset> - <div class="form-group col-md-8"> - <label for="userId">{{'users.attributes.user_id' |translate}}</label> - <input type="text" class="form-control" formControlName="userId" id="userId" - [ngClass]="valid('userId')" - placeholder="{{'users.input.user_id'|translate}}"> - <small>{{'users.input.small.user_id'|translate}}</small> + <div class="form-group col-md-8"> + <label for="user_id">{{'users.attributes.user_id' |translate}}</label> + <input type="text" class="form-control" formControlName="user_id" id="user_id" + [ngClass]="valid('user_id')" + placeholder="{{'users.input.user_id'|translate}}"> + <small>{{'users.input.small.user_id'|translate:{'minSize':this.minUserIdSize} }}</small> + </div> + <div class="form-group col-md-8"> + <label for="full_name">{{'users.attributes.full_name' |translate}}</label> + <input type="text" class="form-control" formControlName="full_name" id="full_name" + [ngClass]="valid('full_name')" + placeholder="{{'users.input.full_name'|translate}}"> + <small>{{'users.input.small.full_name'|translate}}</small> + </div> + <div class="form-group col-md-8"> + <label for="email">{{'users.attributes.email' |translate}}</label> + <input type="text" class="form-control" formControlName="email" id="email" + [ngClass]="valid('email')" + placeholder="{{'users.input.email'|translate}}"> + </div> + <div class="form-group col-md-8"> + <label for="password">{{'users.attributes.password' |translate}}</label> + <input type="password" class="form-control" formControlName="password" id="password" + [ngClass]="valid('password')" + placeholder="{{'users.input.password'|translate}}"> + </div> + <div class="form-group col-md-8"> + <label for="confirm_password">{{'users.attributes.confirm_password' |translate}}</label> + <input type="password" class="form-control" formControlName="confirm_password" id="confirm_password" + [ngClass]="valid('confirm_password')" + placeholder="{{'users.input.confirm_password'|translate}}"> + </div> + <div class="form-group col-md-8"> + <div class="form-check"> + <input class="form-check-input" type="checkbox" value="" formControlName="locked" id="locked"> + <label class="form-check-label" for="locked"> + {{'users.attributes.locked'|translate}} + </label> </div> - <div class="form-group col-md-8"> - <label for="fullName">{{'users.attributes.full_name' |translate}}</label> - <input type="text" class="form-control" formControlName="fullName" id="fullName" - [ngClass]="valid('fullName')" - placeholder="{{'users.input.full_name'|translate}}"> - <small>{{'users.input.small.full_name'|translate}}</small> + <div class="form-check"> + <input class="form-check-input" type="checkbox" value="" formControlName="password_change_required" + id="password_change_required" checked> + <label class="form-check-label" for="password_change_required"> + {{'users.attributes.password_change_required'|translate}} + </label> </div> - <div class="form-group col-md-8"> - <label for="email">{{'users.attributes.email' |translate}}</label> - <input type="text" class="form-control" formControlName="email" id="email" - [ngClass]="valid('email')" - placeholder="{{'users.input.email'|translate}}"> - </div> - <div class="form-group col-md-8"> - <div class="form-check"> - <input class="form-check-input" type="checkbox" value="" formControlName="locked" id="locked"> - <label class="form-check-label" for="locked"> - {{'users.attributes.locked'|translate}} - </label> - </div> - <div class="form-check"> - <input class="form-check-input" type="checkbox" value="" formControlName="passwordChangeRequired" - id="password_change_required" checked> - <label class="form-check-label" for="password_change_required"> - {{'users.attributes.password_change_required'|translate}} - </label> - </div> - </div> - <div class="form-group col-md-8"> + </div> + <div class="form-group col-md-8"> <button class="btn btn-primary" type="submit" [disabled]="!userForm.valid">{{'users.add.submit'|translate}}</button> - </div> - </fieldset> + </div> + <div *ngIf="success" class="alert alert-success" role="alert"> + User <a [routerLink]="['user','users','edit',userid]">{{userid}}</a> was added to the list. + </div> + <div *ngIf="error" class="alert alert-danger" role="alert" > + <h4 class="alert-heading">Errors</h4> + <ng-container *ngFor="let message of errorResult?.error_messages; first as isFirst" > + <hr *ngIf="!isFirst"> + <p>{{message.message}}</p> + </ng-container> + </div> </form> diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts index ce95bff62..6a50028b7 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-add/manage-users-add.component.ts @@ -18,8 +18,14 @@ */ import {Component, OnInit} from '@angular/core'; -import {FormControl, FormGroup, Validators, FormBuilder} from '@angular/forms'; +import {Validators, FormBuilder, FormGroup} from '@angular/forms'; import {UserService} from "../../../../services/user.service"; +import {User} from "../../../../model/user"; +import { UserInfo } from 'src/app/model/user-info'; +import {HttpErrorResponse} from "@angular/common/http"; +import {ErrorResult} from "../../../../model/error-result"; +import {catchError} from "rxjs/operators"; +import {of, throwError} from 'rxjs'; @Component({ selector: 'app-manage-users-add', @@ -28,12 +34,23 @@ import {UserService} from "../../../../services/user.service"; }) export class ManageUsersAddComponent implements OnInit { + minUserIdSize=8; + success:boolean=false; + error:boolean=false; + errorResult:ErrorResult; + result:string; + userid:string; + userForm = this.fb.group({ - userId: ['', [Validators.required, Validators.minLength(8)]], - fullName: ['', Validators.required], + user_id: ['', [Validators.required, Validators.minLength(this.minUserIdSize)]], + full_name: ['', Validators.required], email: ['', [Validators.required,Validators.email]], locked: [false], - passwordChangeRequired: [true] + password_change_required: [true], + password: [''], + confirm_password: [''], + }, { + validator: MustMatch('password', 'confirm_password') }) constructor(private userService: UserService, private fb: FormBuilder) { @@ -45,13 +62,41 @@ export class ManageUsersAddComponent implements OnInit { onSubmit() { // Process checkout data here - console.warn('Your order has been submitted', JSON.stringify(this.userForm.value)); + this.result=null; + if (this.userForm.valid) { + let user = this.copyForm(['user_id','full_name','email','locked','password_change_required', + 'password','confirm_password']) + console.info('Adding user ' + user); + this.userService.addUser(user).pipe(catchError((error : ErrorResult)=> { + console.log("Error " + error + " - " + typeof (error) + " - " + JSON.stringify(error)); + if (error.status==422) { + console.warn("Validation error"); + + } + this.errorResult = error; + this.success=false; + this.error=true; + return throwError(error); + })).subscribe((location : string ) => { + this.result = location; + this.success=true; + this.error = false; + this.userid = location.substring(location.lastIndexOf('/') + 1); + }); + } } - get userId() { - return this.userForm.get('userId'); + + private copyForm(properties:string[]) : User { + let user : any = new User(); + for (let prop of properties) { + user[prop] = this.userForm.get(prop).value; + } + console.log("User " + user); + return user; } + valid(field:string) : string { let formField = this.userForm.get(field); if (formField.dirty||formField.touched) { @@ -65,4 +110,26 @@ export class ManageUsersAddComponent implements OnInit { } } + + + } + +export function MustMatch(controlName: string, matchingControlName: string) { + return (formGroup: FormGroup) => { + const control = formGroup.controls[controlName]; + const matchingControl = formGroup.controls[matchingControlName]; + + if (matchingControl.errors && !matchingControl.errors.mustMatch) { + // return if another validator has already found an error on the matchingControl + return; + } + + // set error on matchingControl if validation fails + if (control.value !== matchingControl.value) { + matchingControl.setErrors({ mustMatch: true }); + } else { + matchingControl.setErrors(null); + } + } +}
\ No newline at end of file diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.html b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.html index fbd689508..960e16d3a 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.html +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/user/users/manage-users-list/manage-users-list.component.html @@ -50,7 +50,7 @@ [ngClass]="user.validated?'fa-check-circle':'fa-circle'"></span></td> <td><span class="far" [attr.aria-valuetext]="user.locked" [ngClass]="user.locked?'fa-check-circle':'fa-circle'"></span></td> - <td><span class="far" [attr.aria-valuetext]="user.passwordChangeRequired" + <td><span class="far" [attr.aria-valuetext]="user.password_change_required" [ngClass]="user.password_change_required?'fa-check-circle':'fa-circle'"></span></td> <td>{{user.timestamp_last_login | date:'yyyy-MM-ddTHH:mm:ss'}}</td> <td>{{user.timestamp_account_creation | date : 'yyyy-MM-ddTHH:mm:ss'}}</td> diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/archiva-request.service.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/archiva-request.service.ts index 0227893c1..2f1e9939f 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/archiva-request.service.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/archiva-request.service.ts @@ -17,11 +17,12 @@ * under the License. */ import {Injectable} from '@angular/core'; -import {HttpClient} from "@angular/common/http"; +import {HttpClient, HttpErrorResponse, HttpResponse} from "@angular/common/http"; import {environment} from "../../environments/environment"; import {Observable} from "rxjs"; import {ErrorMessage} from "../model/error-message"; import {TranslateService} from "@ngx-translate/core"; +import {ErrorResult} from "../model/error-result"; @Injectable({ providedIn: 'root' @@ -42,6 +43,21 @@ export class ArchivaRequestService { * @param input the input data, if this is a POST or UPDATE request */ executeRestCall<R>(type: string, module: string, service: string, input: object): Observable<R> { + let httpArgs = this.getHttpOptions(type, module, service, input); + httpArgs['options']['observe'] = 'body'; + httpArgs['options']['responseType'] = 'json'; + + let lType = type.toLowerCase(); + if (lType == "get") { + return this.http.get<R>(httpArgs.url, httpArgs.options); + } else if (lType == "head" ) { + return this.http.head<R>(httpArgs.url, httpArgs.options); + } else if (lType == "post") { + return this.http.post<R>(httpArgs.url, input, httpArgs.options); + } + } + + private getHttpOptions(type: string, module: string, service: string, input: object) { let modulePath = environment.application.servicePaths[module]; let url = environment.application.baseUrl + environment.application.restPath + "/" + modulePath + "/" + service; let token = this.getToken(); @@ -53,14 +69,28 @@ export class ArchivaRequestService { } else { headers = {}; } - if (type == "get") { + let options = {'headers': headers} + if (type.toLowerCase()=='get') { let params = {} if (input!=null) { params = input; } - return this.http.get<R>(url, {"headers": headers,"params":params}); - } else if (type == "post") { - return this.http.post<R>(url, input, {"headers": headers}); + options['params'] = params; + } + return {'url':url, 'options':options} + } + + executeResponseCall<R>(type: string, module: string, service:string, input:object) : Observable<HttpResponse<R>> { + let httpArgs = this.getHttpOptions(type, module, service, input); + httpArgs['options']['observe'] = 'response'; + httpArgs['options']['responseType'] = 'json'; + let lType = type.toLowerCase(); + if (lType == "get") { + return this.http.get<HttpResponse<R>>(httpArgs.url, httpArgs.options); + } else if (lType=='head') { + return this.http.head<HttpResponse<R>>(httpArgs.url, httpArgs.options); + } else if (lType == 'post') { + return this.http.post<HttpResponse<R>>(httpArgs.url, input, httpArgs.options); } } @@ -97,4 +127,17 @@ export class ArchivaRequestService { return this.translator.instant('api.' + errorMsg.error_key, parms); } } + + public getTranslatedErrorResult(httpError : HttpErrorResponse) : ErrorResult { + let errorResult = httpError.error as ErrorResult; + errorResult.status = httpError.status; + if (errorResult.error_messages!=null) { + for (let message of errorResult.error_messages) { + if (message.message==null || message.message=='') { + message.message = this.translateError(message); + } + } + } + return errorResult; + } } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/user.service.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/user.service.ts index 1792ec805..d3b8e9a87 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/user.service.ts +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/user.service.ts @@ -19,12 +19,14 @@ import {Injectable, OnDestroy, OnInit} from '@angular/core'; import {ArchivaRequestService} from "./archiva-request.service"; import {UserInfo} from '../model/user-info'; -import {HttpErrorResponse} from "@angular/common/http"; +import {HttpErrorResponse, HttpResponse} from "@angular/common/http"; import {ErrorResult} from "../model/error-result"; -import {Observable} from "rxjs"; +import {Observable, throwError} from "rxjs"; import {Permission} from '../model/permission'; import {PagedResult} from "../model/paged-result"; import {EntityService} from "../model/entity-service"; +import { User } from '../model/user'; +import {catchError, map} from "rxjs/operators"; @Injectable({ providedIn: 'root' @@ -269,4 +271,11 @@ export class UserService implements OnInit, OnDestroy { return this.rest.executeRestCall<PagedResult<UserInfo>>("get", "redback", "users", {'q':searchTerm, 'offset':offset,'limit':limit,'orderBy':orderBy,'order':order}); } + + public addUser(user : User) : Observable<string> { + return this.rest.executeResponseCall<string>("post", "redback", "users", user).pipe( + catchError( ( error: HttpErrorResponse) => { + return throwError(this.rest.getTranslatedErrorResult(error)); + }),map( (httpResponse : HttpResponse<string>) => httpResponse.headers.get('Location'))); + } } diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json index 02a32fd84..05843c492 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json @@ -47,7 +47,8 @@ } }, "api" : { - "rb.auth.invalid_credentials": "Invalid credentials given" + "rb.auth.invalid_credentials": "Invalid credentials given", + "user.password.violation.numeric" : "Password must have at least {{arg0}} numeric characters." }, "users": { "attributes":{ @@ -61,16 +62,20 @@ "last_login": "Last Login", "created": "Created", "permanent": "Permanent", - "last_password_change": "Last Password Change" + "last_password_change": "Last Password Change", + "password": "Password", + "confirm_password": "Confirm Password" }, "input" : { "small": { - "user_id": "Must be a unique key. No space allowed.", + "user_id": "Must be a unique key with at least {{minSize}} characters. No spaces allowed.", "full_name": "This is the display name of the user" }, "user_id": "Enter user ID", "full_name": "Enter full user name", - "email": "email@example.org" + "email": "email@example.org", + "password": "Enter password", + "confirm_password": "Confirm password" }, "list": { @@ -88,5 +93,10 @@ }, "form": { "submit": "Submit" + }, + "password": { + "violations" : { + + } } }
\ No newline at end of file |