mirror of https://github.com/apache/archiva.git
Updating user add component
This commit is contained in:
parent
1caa397790
commit
055964cce1
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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')));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" : {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue