This is an automated email from the ASF dual-hosted git repository.

martin_s pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/archiva.git

commit 055964cce1d8c3b272227520836cd494048ab3e4
Author: Martin Stockhammer <[email protected]>
AuthorDate: Wed Nov 11 21:01:46 2020 +0100

    Updating user add component
---
 .../main/archiva-web/src/app/model/error-result.ts |  1 +
 .../app/model/{error-result.ts => user.spec.ts}    | 14 ++--
 .../src/app/model/{error-result.ts => user.ts}     | 11 +--
 .../user/manage-users/manage-users.component.html  |  3 +
 .../manage-users-add.component.html                | 94 +++++++++++++---------
 .../manage-users-add/manage-users-add.component.ts | 81 +++++++++++++++++--
 .../manage-users-list.component.html               |  2 +-
 .../src/app/services/archiva-request.service.ts    | 53 ++++++++++--
 .../archiva-web/src/app/services/user.service.ts   | 13 ++-
 .../src/main/archiva-web/src/assets/i18n/en.json   | 18 ++++-
 10 files changed, 219 insertions(+), 71 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 64e9765..b54fa84 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/error-result.ts
 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/user.spec.ts
similarity index 78%
copy from 
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/error-result.ts
copy to 
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/user.spec.ts
index 64e9765..40e1437 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/user.spec.ts
@@ -16,12 +16,10 @@
  * under the License.
  */
 
-import {ErrorMessage} from "./error-message";
+import { User } from './user';
 
-export class ErrorResult {
-    error_messages: Array<ErrorMessage>
-
-    constructor(errorMessages: Array<ErrorMessage>) {
-        this.error_messages = errorMessages;
-    }
-}
+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/error-result.ts
 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/user.ts
similarity index 78%
copy from 
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/error-result.ts
copy to 
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/user.ts
index 64e9765..f264d02 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/user.ts
@@ -16,12 +16,9 @@
  * under the License.
  */
 
-import {ErrorMessage} from "./error-message";
+import { UserInfo } from './user-info';
 
-export class ErrorResult {
-    error_messages: Array<ErrorMessage>
-
-    constructor(errorMessages: Array<ErrorMessage>) {
-        this.error_messages = errorMessages;
-    }
+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 c617180..08b3fca 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 1bfac66..ad538a8 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 ce95bff..6a50028 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 fbd6895..960e16d 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 0227893..2f1e993 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 1792ec8..d3b8e9a 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 02a32fd..05843c4 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 protected]"
+      "email": "[email protected]",
+      "password": "Enter password",
+      "confirm_password": "Confirm password"
     },
 
     "list": {
@@ -88,5 +93,10 @@
   },
   "form": {
     "submit": "Submit"
+  },
+  "password": {
+    "violations" : {
+
+    }
   }
 }
\ No newline at end of file

Reply via email to