Code development platform for open source projects from the European Union institutions :large_blue_circle: EU Login authentication by SMS will be completely phased out by mid-2025. To see alternatives please check here

Skip to content
Snippets Groups Projects
Commit cfcfe0eb authored by Sebastian-Ion TINCU's avatar Sebastian-Ion TINCU
Browse files

EDELIVERY-3687 SMP UI Add/Edit user

Rename roles to match those defined in the back-end.
Fix wrong role binding when adding or editing users.
Fix missing id and status properties.
Improve user resource annotations.
parent 139df850
No related branches found
No related tags found
No related merge requests found
......@@ -18,6 +18,6 @@ export class AuthorizedAdminGuard extends AuthorizedGuard {
getAllowedRoles(route: ActivatedRouteSnapshot): Array<Role> {
// TODO check if we need the SMP admin in here
return [Role.SYSTEM_ADMINISTRATOR/*, Role.SMP_ADMINISTRATOR*/];
return [Role.SYSTEM_ADMIN/*, Role.SMP_ADMIN*/];
}
}
......@@ -2,13 +2,13 @@ export enum Role {
/**
* The system administrator (a.k.a. the "super admin") role
*/
SYSTEM_ADMINISTRATOR = 'System Administrator',
SYSTEM_ADMIN = 'System Administrator',
/**
* The SMP Administrator role. It is assimilable to the {@link SERVICE_GROUP_ADMINISTRATOR} role for now.
* The SMP Administrator role. It is assimilable to the {@link SERVICE_GROUP_ADMIN} role for now.
*/
SMP_ADMINISTRATOR = 'SMP Administrator',
SMP_ADMIN = 'SMP Administrator',
/**
* The ServiceGroup administrator role
*/
SERVICE_GROUP_ADMINISTRATOR = 'ServiceGroup Administrator',
SERVICE_GROUP_ADMIN = 'ServiceGroup Administrator',
}
......@@ -82,11 +82,11 @@ export class SecurityService {
}
isCurrentUserSuperAdmin(): boolean {
return this.isCurrentUserInRole([Role.SYSTEM_ADMINISTRATOR]);
return this.isCurrentUserInRole([Role.SYSTEM_ADMIN]);
}
isCurrentUserAdmin(): boolean {
return this.isCurrentUserInRole([Role.SYSTEM_ADMINISTRATOR, Role.SMP_ADMINISTRATOR]);
return this.isCurrentUserInRole([Role.SYSTEM_ADMIN, Role.SMP_ADMIN]);
}
isCurrentUserInRole(roles: Array<Role>): boolean {
......
......@@ -24,6 +24,8 @@ export class UserDetailsDialogComponent {
readonly passwordPattern = '^(?=.*[A-Z])(?=.*[ !#$%&\'()*+,-./:;<=>?@\\[^_`{|}~\\\]"])(?=.*[0-9])(?=.*[a-z]).{8,32}$';
readonly dateFormat: string = 'yyyy-MM-dd HH:mm:ssZ';
id: number;
editMode: boolean;
formTitle: string;
userRoles = [];
......@@ -65,7 +67,9 @@ export class UserDetailsDialogComponent {
@Inject(MAT_DIALOG_DATA) public data: any,
private fb: FormBuilder) {
this.editMode = data.edit;
this.formTitle = this.editMode ? UserDetailsDialogComponent.EDIT_MODE: UserDetailsDialogComponent.NEW_MODE;
this.id = data.row && data.row.id;
this.formTitle = this.editMode ? UserDetailsDialogComponent.EDIT_MODE: UserDetailsDialogComponent.NEW_MODE;
const user: UserRo & { confirmation?: string } = this.editMode
? {
......@@ -78,14 +82,13 @@ export class UserDetailsDialogComponent {
validTo: data.row.validTo,
issuer: data.row.issuer,
serialNumber: data.row.serialNumber,
}
},
}: {
username: '',
email: '',
password: '',
confirmation: '',
role: '',
status: SearchTableEntityStatus.NEW,
certificate: {},
};
......@@ -94,7 +97,7 @@ export class UserDetailsDialogComponent {
this.userForm = fb.group({
'userToggle': new FormControl(userDetailsToggled),
'username': new FormControl({ value: user.username, disabled: this.editMode || !userDetailsToggled }, this.editMode ? Validators.nullValidator : null),
'role': new FormControl({ value: user.role, disabled: !userDetailsToggled }, Validators.required),
'role': new FormControl({ value: Role[user.role], disabled: !userDetailsToggled }, Validators.required),
'password': new FormControl({ value: user.password, disabled: !userDetailsToggled }, [Validators.required, Validators.pattern(this.passwordPattern)]),
'confirmation': new FormControl({ value: user.password, disabled: !userDetailsToggled }, Validators.pattern(this.passwordPattern)),
......@@ -113,6 +116,7 @@ export class UserDetailsDialogComponent {
this.existingRoles = this.editMode
? this.getAllowedRoles(this.userRoles, user.role)
: this.userRoles;
console.log(this.userRoles, this.existingRoles);
});
}
......@@ -155,15 +159,22 @@ export class UserDetailsDialogComponent {
}
get current(): UserRo {
return this.userForm.getRawValue();
const rawValue = this.userForm.getRawValue();
return {
...rawValue,
id: this.id,
role: Object.keys(Role).find(k => Role[k] === rawValue.role), // ugly hack to find the corresponding enum key as a string
status: this.id ? SearchTableEntityStatus.UPDATED: SearchTableEntityStatus.NEW,
};
}
// filters out roles so that the user cannot change from system administrator to the other roles or vice-versa
private getAllowedRoles(allRoles, userRole) {
if (userRole === Role.SYSTEM_ADMINISTRATOR) {
return [Role.SYSTEM_ADMINISTRATOR];
if (userRole === Role.SYSTEM_ADMIN) {
return [Role.SYSTEM_ADMIN];
} else {
return allRoles.filter(role => role !== Role.SYSTEM_ADMINISTRATOR);
return allRoles.filter(role => role !== Role.SYSTEM_ADMIN);
}
}
}
......@@ -8,6 +8,8 @@
[showSearchPanel]="false"
[filter]="filter">
<ng-template #roleCellTemplate let-value="value" ngx-datatable-cell-template>{{getRoleLabel(value)}}</ng-template>
<ng-template #additionalToolButtons></ng-template>
</smp-search-table>
......@@ -4,6 +4,8 @@ import {MatDialog, MatDialogRef} from '@angular/material';
import {AlertService} from '../alert/alert.service';
import {UserController} from './user-controller';
import {HttpClient} from '@angular/common/http';
import {Role} from "../security/role.model";
import {UserRo} from "./user-ro.model";
@Component({
templateUrl:'./user.component.html',
......@@ -11,9 +13,7 @@ import {HttpClient} from '@angular/common/http';
})
export class UserComponent implements OnInit {
@ViewChild('rowMetadataAction') rowMetadataAction: TemplateRef<any>
@ViewChild('rowExtensionAction') rowExtensionAction: TemplateRef<any>
@ViewChild('rowActions') rowActions: TemplateRef<any>;
@ViewChild('roleCellTemplate') roleCellTemplate: TemplateRef<any>
columnPicker: ColumnPicker = new ColumnPicker();
userController: UserController;
......@@ -37,6 +37,7 @@ export class UserComponent implements OnInit {
canAutoResize: true
},
{
cellTemplate: this.roleCellTemplate,
name: 'Role',
prop: 'role',
canAutoResize: true
......@@ -51,4 +52,8 @@ export class UserComponent implements OnInit {
details(row: any) {
this.userController.showDetails(row);
}
getRoleLabel(role: string): Role {
return Role[role];
}
}
......@@ -11,6 +11,6 @@ export class UserService {
getUserRoles$() {
// return this.http.get('rest/user/userroles');
// TODO create the endpoint
return of({json: () => [Role.SYSTEM_ADMINISTRATOR, Role.SMP_ADMINISTRATOR, Role.SERVICE_GROUP_ADMINISTRATOR]});
return of({json: () => [Role.SYSTEM_ADMIN, Role.SMP_ADMIN, Role.SERVICE_GROUP_ADMIN]});
}
}
package eu.europa.ec.edelivery.smp.ui;
import eu.europa.ec.edelivery.smp.data.ui.CertificateRO;
import eu.europa.ec.edelivery.smp.data.ui.DomainRO;
import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
import eu.europa.ec.edelivery.smp.data.ui.UserRO;
import eu.europa.ec.edelivery.smp.logging.SMPLogger;
import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
import eu.europa.ec.edelivery.smp.services.ui.UIUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.util.Arrays;
......@@ -38,43 +34,31 @@ public class UserResource {
@Autowired
private UIUserService uiUserService;
@PostConstruct
protected void init() {
}
@PutMapping(produces = {"application/json"})
@GetMapping
@ResponseBody
@RequestMapping(method = RequestMethod.GET)
public ServiceResult<UserRO> getUsers(
@RequestParam(value = "page", defaultValue = "0") int page,
@RequestParam(value = "pageSize", defaultValue = "10") int pageSize,
@RequestParam(value = "orderBy", required = false) String orderBy,
@RequestParam(value = "orderType", defaultValue = "asc", required = false) String orderType,
@RequestParam(value = "user", required = false) String user
) {
@RequestParam(value = "user", required = false) String user) {
return uiUserService.getTableList(page,pageSize, orderBy, orderType, null);
}
@PutMapping(produces = {"application/json"})
@RequestMapping(method = RequestMethod.PUT)
public void updateUserList(@RequestBody(required = true) UserRO[] updateEntities ){
LOG.info("Update user list, count: {}" + updateEntities.length);
LOG.info("Update user list, count: {}", updateEntities.length);
uiUserService.updateUserList(Arrays.asList(updateEntities));
}
@RequestMapping(path = "certdata", method = RequestMethod.POST)
@PostMapping(path = "certdata")
public CertificateRO uploadFile(@RequestBody byte[] data) {
LOG.info("Got certificate data: " + data.length);
try {
return uiUserService.getCertificateData(data);
} catch (CertificateException e) {
LOG.error("Error occured while parsing certificate.", e);
LOG.error("Error occurred while parsing certificate.", e);
}
return null;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment