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 a7b74c90 authored by Joze RIHTARSIC's avatar Joze RIHTARSIC
Browse files

[EDELIVERY-11679] Alert page for users feature implementation

parent da24a196
No related branches found
No related tags found
No related merge requests found
Pipeline #123250 passed with warnings
Showing
with 290 additions and 92 deletions
import {AlertRo} from './alert-ro.model';
export interface AlertResult {
serviceEntities: Array<AlertRo>;
pageSize: number;
count: number;
filter: any;
}
import 'hammerjs';
import {AccessTokenPanelComponent} from "./user-settings/user-access-tokens/access-token-panel/access-token-panel.component";
import {AlertPanelComponent} from "./common/panels/alert-panel/alert-panel.component";
import {AdminAlertsComponent} from "./system-settings/admin-alerts/admin-alerts.component";
import {AdminDomainComponent} from "./system-settings/admin-domain/admin-domain.component";
import {AdminDomainService} from "./system-settings/admin-domain/admin-domain.service";
import {AdminKeystoreComponent} from "./system-settings/admin-keystore/admin-keystore.component";
import {AdminKeystoreService} from "./system-settings/admin-keystore/admin-keystore.service";
import {AdminTruststoreComponent} from "./system-settings/admin-truststore/admin-truststore.component";
import {AdminTruststoreService} from "./system-settings/admin-truststore/admin-truststore.service";
import {AlertComponent} from "./alert/alert.component";
import {AlertMessageComponent} from './common/alert-message/alert-message.component';
import {AlertMessageService} from './common/alert-message/alert-message.service';
import {AppComponent} from './app.component';
......@@ -142,15 +143,17 @@ import {SmpTitledLabelComponent} from "./common/components/smp-titled-label/smp-
import {ServiceGroupSearchComponent} from "./service-group-search/service-group-search.component";
import {EditResourceController} from "./edit/edit-resources/edit-resource.controller";
import { ClipboardModule } from '@angular/cdk/clipboard';
import {UserAlertsComponent} from "./user-settings/user-alerts/user-alerts.component";
@NgModule({
declarations: [
AccessTokenPanelComponent,
AdminAlertsComponent,
AdminDomainComponent,
AdminKeystoreComponent,
AdminTruststoreComponent,
AdminUserComponent,
AlertComponent,
AlertPanelComponent,
AlertMessageComponent,
AppComponent,
AutoFocusDirective,
......@@ -220,6 +223,7 @@ import { ClipboardModule } from '@angular/cdk/clipboard';
SubresourceDocumentWizardComponent,
SubresourcePanelComponent,
ToolbarComponent,
UserAlertsComponent,
UserAccessTokensComponent,
UserCertificatePanelComponent,
UserCertificatesComponent,
......
import {RouterModule, Routes} from '@angular/router';
import {LoginComponent} from './login/login.component';
import {ServiceGroupSearchComponent} from './service-group-search/service-group-search.component';
import {AlertComponent} from "./alert/alert.component";
import {PropertyComponent} from "./system-settings/property/property.component";
import {UserProfileComponent} from "./user-settings/user-profile/user-profile.component";
import {authenticationGuard} from "./guards/authentication.guard";
......@@ -20,6 +19,8 @@ import {ResourceDocumentPanelComponent} from "./edit/edit-resources/resource-doc
import {SubresourceDocumentPanelComponent} from "./edit/edit-resources/subresource-document-panel/subresource-document-panel.component";
import {authorizeChildSystemAdminGuard} from "./guards/authorize-child-system-admin.guard";
import {activateChildResourceGuard} from "./guards/activate-child-document.guard";
import {UserAlertsComponent} from "./user-settings/user-alerts/user-alerts.component";
import {AdminAlertsComponent} from "./system-settings/admin-alerts/admin-alerts.component";
const appRoutes: Routes = [
......@@ -37,8 +38,18 @@ const appRoutes: Routes = [
path: 'edit-resource',
canDeactivate: [dirtyDeactivateGuard],
children: [
{path: 'resource-document', canActivate: [activateChildResourceGuard], component: ResourceDocumentPanelComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'subresource-document', canActivate: [activateChildResourceGuard], component: SubresourceDocumentPanelComponent, canDeactivate: [dirtyDeactivateGuard]},
{
path: 'resource-document',
canActivate: [activateChildResourceGuard],
component: ResourceDocumentPanelComponent,
canDeactivate: [dirtyDeactivateGuard]
},
{
path: 'subresource-document',
canActivate: [activateChildResourceGuard],
component: SubresourceDocumentPanelComponent,
canDeactivate: [dirtyDeactivateGuard]
},
{path: '', component: EditResourceComponent, canDeactivate: [dirtyDeactivateGuard]},
]
}
......@@ -54,7 +65,7 @@ const appRoutes: Routes = [
{path: 'keystore', component: AdminKeystoreComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'truststore', component: AdminTruststoreComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'extension', component: ExtensionComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'alert', component: AlertComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'alert', component: AdminAlertsComponent, canDeactivate: [dirtyDeactivateGuard]},
]
},
{
......@@ -64,6 +75,7 @@ const appRoutes: Routes = [
{path: 'user-profile', component: UserProfileComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'user-access-token', component: UserAccessTokensComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'user-certificate', component: UserCertificatesComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'user-alert', component: UserAlertsComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'user-membership', component: UserProfileComponent, canDeactivate: [dirtyDeactivateGuard]},
]
},
......
......@@ -8,9 +8,6 @@
<mat-icon>check_circle</mat-icon>
<span>Yes</span>
</button>
</div>
<div *ngIf="isConfirmationDialog()" class="divTableCell">
<button mat-raised-button color="primary" (click)="dialogRef.close(false)" id="nobuttondialog_id" tabindex="1">
<mat-icon>cancel</mat-icon>
<span>No</span>
......
import {SearchTableController} from '../common/search-table/search-table-controller';
import {SearchTableController} from '../../search-table/search-table-controller';
import {MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material/dialog';
import {GlobalLookups} from "../common/global-lookups";
import {SearchTableEntity} from "../common/search-table/search-table-entity.model";
import {HttpClient} from "@angular/common/http";
import {ObjectPropertiesDialogComponent} from "../common/dialogs/object-properties-dialog/object-properties-dialog.component";
import {GlobalLookups} from "../../global-lookups";
import {SearchTableEntity} from "../../search-table/search-table-entity.model";
import {ObjectPropertiesDialogComponent} from "../../dialogs/object-properties-dialog/object-properties-dialog.component";
export class AlertController implements SearchTableController {
constructor(protected http: HttpClient, protected lookups: GlobalLookups, public dialog: MatDialog) {
constructor(protected lookups: GlobalLookups, public dialog: MatDialog) {
}
validateDeleteOperation(rows: SearchTableEntity[]) {
......
<smp-search-table
#searchTable
page_id='alert_id'
[title]="'Alerts'"
[columnPicker]="columnPicker"
[url]="baseUrl"
......@@ -17,14 +16,15 @@
<span style="width: 2px">&nbsp;</span>
</ng-template>
<ng-template #dateTimeColumn let-value="value" ngx-datatable-cell-template>
<div class='truncate-text' title="{{value | date:dateTimeFormat}}" >{{value | date:dateFormat}}</div></ng-template>
<ng-template #truncateText let-value="value" ngx-datatable-cell-template>
<div class='truncate-text' title="{{value}}" >{{value}}</div>
<div class='truncate-text' title="{{value | date:dateTimeFormat}}">{{ value | date:dateTimeFormat }}</div>
</ng-template>
<ng-template #forUser let-row="row" let-value="value" ngx-datatable-cell-template>
<div class='truncate-text' title="{{value}} (Email:'{{row.mailTo}}')" >{{value}}</div>
<ng-template #truncateText let-value="value" ngx-datatable-cell-template>
<div class='truncate-text' title="{{value}}">{{ value }}</div>
</ng-template>
<ng-template #credentialType let-row="row" let-value="value" ngx-datatable-cell-template>
<div class='truncate-text' >{{value['CREDENTIAL_TYPE']}}</div>
<ng-template #forUser let-row="row" let-value="value" ngx-datatable-cell-template>
<div class='truncate-text' title="{{value}} (Email:'{{row.mailTo}}')">{{ value }}</div>
</ng-template>
<ng-template #credentialType let-row="row" let-value="value" ngx-datatable-cell-template>
<div class='truncate-text'>{{ value['CREDENTIAL_TYPE'] }}</div>
</ng-template>
</smp-search-table>
......@@ -2,29 +2,32 @@ import {
AfterViewChecked,
AfterViewInit,
ChangeDetectorRef,
Component,
Component, Input,
OnInit,
TemplateRef,
ViewChild
} from '@angular/core';
import {ColumnPicker} from '../common/column-picker/column-picker.model';
import {ColumnPicker} from '../../column-picker/column-picker.model';
import {MatDialog} from '@angular/material/dialog';
import {AlertMessageService} from '../common/alert-message/alert-message.service';
import {AlertMessageService} from '../../alert-message/alert-message.service';
import {AlertController} from './alert-controller';
import {HttpClient} from '@angular/common/http';
import {SmpConstants} from "../smp.constants";
import {GlobalLookups} from "../common/global-lookups";
import {SearchTableComponent} from "../common/search-table/search-table.component";
import {SecurityService} from "../security/security.service";
import {ObjectPropertiesDialogComponent} from "../common/dialogs/object-properties-dialog/object-properties-dialog.component";
import {SmpConstants} from "../../../smp.constants";
import {GlobalLookups} from "../../global-lookups";
import {SearchTableComponent} from "../../search-table/search-table.component";
import {SecurityService} from "../../../security/security.service";
import {ObjectPropertiesDialogComponent} from "../../dialogs/object-properties-dialog/object-properties-dialog.component";
/**
* This is a generic alert panel component for previewing alert list
*/
@Component({
templateUrl: './alert.component.html',
styleUrls: ['./alert.component.css']
selector: 'alert-panel',
templateUrl: './alert-panel.component.html',
styleUrls: ['./alert-panel.component.css']
})
export class AlertComponent implements OnInit, AfterViewInit, AfterViewChecked {
export class AlertPanelComponent implements OnInit, AfterViewInit, AfterViewChecked {
@ViewChild('rowMetadataAction') rowMetadataAction: TemplateRef<any>;
@ViewChild('rowActions') rowActions: TemplateRef<any>;
......@@ -34,17 +37,15 @@ export class AlertComponent implements OnInit, AfterViewInit, AfterViewChecked {
@ViewChild('credentialType') credentialType: TemplateRef<any>;
@ViewChild('forUser') forUser: TemplateRef<any>;
readonly dateTimeFormat: string = SmpConstants.DATE_TIME_FORMAT;
readonly dateFormat: string = SmpConstants.DATE_FORMAT;
baseUrl = SmpConstants.REST_INTERNAL_ALERT_MANAGE;
@Input() baseUrl = null;
columnPicker: ColumnPicker = new ColumnPicker();
alertController: AlertController;
filter: any = {};
isSMPIntegrationOn: boolean = false;
constructor(public securityService: SecurityService,
protected lookups: GlobalLookups,
protected http: HttpClient,
......@@ -54,7 +55,7 @@ export class AlertComponent implements OnInit, AfterViewInit, AfterViewChecked {
}
ngOnInit() {
this.alertController = new AlertController(this.http, this.lookups, this.dialog);
this.alertController = new AlertController(this.lookups, this.dialog);
}
ngAfterViewChecked() {
......@@ -68,9 +69,17 @@ export class AlertComponent implements OnInit, AfterViewInit, AfterViewChecked {
title: "Alert date",
prop: 'reportingTime',
showInitially: true,
maxWidth: 100,
maxWidth: 250,
cellTemplate: this.dateTimeColumn,
},
{
name: 'Alert level',
title: "Alert level.",
prop: 'alertLevel',
showInitially: true,
maxWidth: 100,
},
{
name: 'For User',
title: "For User",
......@@ -109,14 +118,6 @@ export class AlertComponent implements OnInit, AfterViewInit, AfterViewChecked {
showInitially: true,
},
{
name: 'Alert level',
title: "Alert level.",
prop: 'alertLevel',
showInitially: true,
maxWidth: 80,
},
];
this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => col.showInitially);
this.searchTable.tableColumnInit();
......@@ -141,6 +142,4 @@ export class AlertComponent implements OnInit, AfterViewInit, AfterViewChecked {
isDirty(): boolean {
return this.searchTable.isDirty();
}
}
import {SearchTableEntity} from '../common/search-table/search-table-entity.model';
import {SearchTableEntity} from '../../search-table/search-table-entity.model';
export interface AlertRo extends SearchTableEntity {
sid: string;
......
......@@ -33,6 +33,7 @@ export class SmpConstants {
public static readonly PATH_PARAM_KEYSTORE_PWD = '{keystore-pwd}';
public static readonly PATH_PARAM_KEYSTORE_TYPE = '{keystore-type}';
public static readonly PATH_RESOURCE_TYPE_ALERT = 'alert';
public static readonly PATH_RESOURCE_TYPE_DOMAIN = 'domain';
public static readonly PATH_RESOURCE_TYPE_MEMBER = 'member';
public static readonly PATH_RESOURCE_TYPE_GROUP = 'group';
......@@ -138,11 +139,13 @@ export class SmpConstants {
// user public services
public static readonly REST_PUBLIC_USER = SmpConstants.REST_PUBLIC + 'user';
public static readonly REST_PUBLIC_USER_UPDATE = SmpConstants.REST_PUBLIC_USER + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/';
public static readonly REST_PUBLIC_USER_GENERATE_ACCESS_TOKEN = SmpConstants.REST_PUBLIC_USER_UPDATE + 'generate-access-token';
public static readonly REST_PUBLIC_USER_CHANGE_PASSWORD = SmpConstants.REST_PUBLIC_USER_UPDATE + 'change-password';
public static readonly REST_PUBLIC_USER_SEARCH = SmpConstants.REST_PUBLIC_USER + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + SmpConstants.PATH_ACTION_SEARCH;
public static readonly REST_PUBLIC_USER_MANAGE = SmpConstants.REST_PUBLIC_USER + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/';
public static readonly REST_PUBLIC_USER_ALERT = SmpConstants.REST_PUBLIC_USER_MANAGE + 'alert';
public static readonly REST_PUBLIC_USER_GENERATE_ACCESS_TOKEN = SmpConstants.REST_PUBLIC_USER_MANAGE + 'generate-access-token';
public static readonly REST_PUBLIC_USER_CHANGE_PASSWORD = SmpConstants.REST_PUBLIC_USER_MANAGE + 'change-password';
public static readonly REST_PUBLIC_USER_SEARCH = SmpConstants.REST_PUBLIC_USER_MANAGE + SmpConstants.PATH_ACTION_SEARCH;
// truststore public services
public static readonly REST_PUBLIC_TRUSTSTORE = SmpConstants.REST_PUBLIC + "truststore/" + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/';
public static readonly REST_PUBLIC_TRUSTSTORE_CERT_VALIDATE = SmpConstants.REST_PUBLIC_TRUSTSTORE + 'validate-certificate';
......@@ -174,7 +177,9 @@ export class SmpConstants {
//------------------------------
// internal endpoints
public static readonly REST_INTERNAL_ALERT_MANAGE = SmpConstants.REST_INTERNAL + 'alert';
public static readonly REST_INTERNAL_ALERT_MANAGE = SmpConstants.REST_INTERNAL + SmpConstants.PATH_RESOURCE_TYPE_ALERT +
'/' + SmpConstants.PATH_PARAM_ENC_USER_ID;
public static readonly REST_INTERNAL_DOMAIN_MANAGE_DEPRECATED = SmpConstants.REST_INTERNAL + SmpConstants.PATH_RESOURCE_TYPE_DOMAIN;
public static readonly REST_INTERNAL_DOMAIN_MANAGE = SmpConstants.REST_INTERNAL + SmpConstants.PATH_RESOURCE_TYPE_DOMAIN +
......
<alert-panel [baseUrl]="adminAlertsUrl"></alert-panel>
import {Component, OnDestroy, OnInit,} from '@angular/core';
import {SecurityService} from "../../security/security.service";
import {User} from "../../security/user.model";
import {UserRo} from "../user/user-ro.model";
import {MatDialog} from "@angular/material/dialog";
import {SecurityEventService} from "../../security/security-event.service";
import {Subscription} from "rxjs";
import {SmpConstants} from "../../smp.constants";
import {BeforeLeaveGuard} from "../../window/sidenav/navigation-on-leave-guard";
@Component({
templateUrl: './admin-alerts.component.html',
styleUrls: ['./admin-alerts.component.scss']
})
export class AdminAlertsComponent implements OnInit, OnDestroy, BeforeLeaveGuard {
currentUserData: UserRo;
loggedInUser: User;
private securityEventServiceSub: Subscription = Subscription.EMPTY;
private onProfileDataChangedEventSub: Subscription = Subscription.EMPTY;
constructor(
private securityService: SecurityService,
private securityEventService: SecurityEventService,
public dialog: MatDialog) {
this.securityEventServiceSub = this.securityEventService.onLoginSuccessEvent().subscribe(() => {
this.updateUserData(this.securityService.getCurrentUser())
}
);
}
get adminAlertsUrl(): string {
return SmpConstants.REST_INTERNAL_ALERT_MANAGE
.replace(SmpConstants.PATH_PARAM_ENC_USER_ID, this.loggedInUser?.userId);
}
ngOnInit(): void {
this.updateUserData(this.securityService.getCurrentUser())
}
ngOnDestroy(): void {
this.securityEventServiceSub.unsubscribe();
this.onProfileDataChangedEventSub.unsubscribe();
}
/**
* This is a Readonly components, and it always returns false.
*/
isDirty(): boolean {
return false;
}
private updateUserData(user: User) {
this.currentUserData = this.convert(user);
this.loggedInUser = user;
}
private convert(user: User): UserRo {
return {
...user,
active: true,
status: undefined,
statusPassword: 0
} as UserRo;
}
}
......@@ -35,7 +35,7 @@ export class UserService {
}
updateUser(user: User) {
this.http.put<User>(SmpConstants.REST_PUBLIC_USER_UPDATE.replace(SmpConstants.PATH_PARAM_ENC_USER_ID, user.userId), user).subscribe(response => {
this.http.put<User>(SmpConstants.REST_PUBLIC_USER_MANAGE.replace(SmpConstants.PATH_PARAM_ENC_USER_ID, user.userId), user).subscribe(response => {
this.notifyProfileDataChanged(response)
this.securityService.updateUserDetails(response);
this.alertService.success('The operation \'update user\' completed successfully.');
......
<alert-panel [baseUrl]="userAlertsUrl"></alert-panel>
import {Component, OnDestroy, OnInit,} from '@angular/core';
import {SecurityService} from "../../security/security.service";
import {User} from "../../security/user.model";
import {UserService} from "../../system-settings/user/user.service";
import {UserRo} from "../../system-settings/user/user-ro.model";
import {MatDialog} from "@angular/material/dialog";
import {SecurityEventService} from "../../security/security-event.service";
import {Subscription} from "rxjs";
import {SmpConstants} from "../../smp.constants";
import {BeforeLeaveGuard} from "../../window/sidenav/navigation-on-leave-guard";
@Component({
templateUrl: './user-alerts.component.html',
styleUrls: ['./user-alerts.component.scss']
})
export class UserAlertsComponent implements OnInit, OnDestroy, BeforeLeaveGuard {
currentUserData: UserRo;
loggedInUser: User;
private securityEventServiceSub: Subscription = Subscription.EMPTY;
private onProfileDataChangedEventSub: Subscription = Subscription.EMPTY;
constructor(
private userService: UserService,
private securityService: SecurityService,
private securityEventService: SecurityEventService,
public dialog: MatDialog) {
this.securityEventServiceSub = this.securityEventService.onLoginSuccessEvent().subscribe(() => {
this.updateUserData(this.securityService.getCurrentUser())
}
);
this.onProfileDataChangedEventSub = userService.onProfileDataChangedEvent().subscribe(updatedUser => {
this.updateUserData(updatedUser);
}
);
}
get userAlertsUrl(): string {
return SmpConstants.REST_PUBLIC_USER_ALERT
.replace(SmpConstants.PATH_PARAM_ENC_USER_ID, this.loggedInUser?.userId);
}
ngOnInit(): void {
this.updateUserData(this.securityService.getCurrentUser())
}
ngOnDestroy(): void {
this.securityEventServiceSub.unsubscribe();
this.onProfileDataChangedEventSub.unsubscribe();
}
/**
* This is a Readonly components, and it always returns false.
*/
isDirty(): boolean {
return false;
}
private updateUserData(user: User) {
this.currentUserData = this.convert(user);
this.loggedInUser = user;
}
private convert(user: User): UserRo {
return {
...user,
active: true,
status: undefined,
statusPassword: 0
} as UserRo;
}
}
......@@ -58,11 +58,12 @@ abstract class UIServiceBase<E extends BaseEntity, R> {
/**
* Method returns UI resource object list for page.
*
* @param page
* @param pageSize
* @param sortField
* @param sortOrder
* @return
* @param page - page number (0..n)
* @param pageSize - page size (0..n) - if -1 return all results
* @param sortField - sort field name (null - sorts by id)
* @param sortOrder - sort order (null - sorts by acs )
* @param filter - filter object (null - no filter)
* @return ServiceResult<R> - list of UI resource objects
*/
public ServiceResult<R> getTableList(int page, int pageSize,
String sortField,
......
......@@ -8,9 +8,9 @@
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
*
* [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and limitations under the Licence.
......@@ -27,6 +27,7 @@ import eu.europa.ec.edelivery.smp.data.model.user.DBUser;
import eu.europa.ec.edelivery.smp.data.ui.*;
import eu.europa.ec.edelivery.smp.logging.SMPLogger;
import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
import eu.europa.ec.edelivery.smp.services.ui.UIAlertService;
import eu.europa.ec.edelivery.smp.services.ui.UIUserService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.MimeTypeUtils;
......@@ -36,8 +37,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.CONTEXT_PATH_PUBLIC_USER;
import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.PARAM_PAGINATION_FILTER;
import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.*;
import static eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils.decryptEntityId;
/**
......@@ -49,14 +49,16 @@ import static eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils.decryptEntit
public class UserController {
private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UserController.class);
protected UIUserService uiUserService;
protected SMPAuthorizationService authorizationService;
protected SMPAuthenticationService authenticationService;
private final UIUserService uiUserService;
private final UIAlertService uiAlertService;
private final SMPAuthorizationService authorizationService;
private final SMPAuthenticationService authenticationService;
public UserController(UIUserService uiUserService, SMPAuthorizationService authorizationService, SMPAuthenticationService authenticationService) {
public UserController(UIUserService uiUserService, SMPAuthorizationService authorizationService, SMPAuthenticationService authenticationService, UIAlertService uiAlertService) {
this.uiUserService = uiUserService;
this.authorizationService = authorizationService;
this.authenticationService = authenticationService;
this.uiAlertService = uiAlertService;
}
@PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userId)")
......@@ -161,7 +163,7 @@ public class UserController {
Long accessTokenId = decryptEntityId(encAccessTokenId);
// delete user credential
CredentialRO result = uiUserService.deleteUserCredentials(userId,
CredentialRO result = uiUserService.deleteUserCredentials(userId,
accessTokenId, CredentialType.ACCESS_TOKEN, CredentialTargetType.REST_API);
// set the same encrypted id so that UI can locate and update it
result.setCredentialId(encAccessTokenId);
......@@ -178,7 +180,7 @@ public class UserController {
Long accessTokenId = decryptEntityId(encAccessTokenId);
// delete user credential
CredentialRO result = uiUserService.updateUserCredentials(userId,
CredentialRO result = uiUserService.updateUserCredentials(userId,
accessTokenId,
CredentialType.ACCESS_TOKEN,
CredentialTargetType.REST_API,
......@@ -216,7 +218,7 @@ public class UserController {
Long userId = decryptEntityId(encUserId);
Long credentialId = decryptEntityId(encCredentialId);
// delete user credential
CredentialRO result = uiUserService.deleteUserCredentials(userId,
CredentialRO result = uiUserService.deleteUserCredentials(userId,
credentialId, CredentialType.CERTIFICATE, CredentialTargetType.REST_API);
// set the same encrypted credential id so that UI can remove it from the list
result.setCredentialId(encCredentialId);
......@@ -232,7 +234,7 @@ public class UserController {
Long userId = decryptEntityId(encUserId);
Long credentialId = decryptEntityId(encCredentialId);
// delete user credential
CredentialRO result = uiUserService.updateUserCredentials(userId,
CredentialRO result = uiUserService.updateUserCredentials(userId,
credentialId,
CredentialType.CERTIFICATE,
CredentialTargetType.REST_API,
......@@ -262,6 +264,35 @@ public class UserController {
return uiUserService.storeCertificateCredentialForUser(userId, credentialRO);
}
/**
* Method returns Users list of alerts. To access the list user must be logged in.
* <p>
*
* @param encUserId - encrypted user id (from session) - used for authorization check
* @param page - page number (0..n)
* @param pageSize - page size (0..n) - number of results on page/max number of returned results.
* @param orderBy - order by field
* @param orderType - order type (asc, desc)
* @return ServiceResult<AlertRO> - list of alerts
*/
@PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#encUserId)")
@GetMapping(path = "/{user-id}/alert", produces = {MimeTypeUtils.APPLICATION_JSON_VALUE})
public ServiceResult<AlertRO> getUserAlertList(
@PathVariable("user-id") String encUserId,
@RequestParam(value = PARAM_PAGINATION_PAGE, defaultValue = "0") int page,
@RequestParam(value = PARAM_PAGINATION_PAGE_SIZE, defaultValue = "10") int pageSize,
@RequestParam(value = PARAM_PAGINATION_ORDER_BY, defaultValue = "id", required = false) String orderBy,
@RequestParam(value = PARAM_PAGINATION_ORDER_TYPE, defaultValue = "desc", required = false) String orderType
) {
LOG.info("Search for page: {}, page size: {}", page, pageSize);
UserRO loggedUserData = authorizationService.getLoggedUserData();
// set filter to current user
AlertRO filter = new AlertRO();
filter.setUsername(loggedUserData.getUsername());
// return the user alert list
return uiAlertService.getTableList(page, pageSize, orderBy, orderType, filter);
}
protected NavigationTreeNodeRO createPublicNavigationTreeNode() {
NavigationTreeNodeRO node = new NavigationTreeNodeRO("search-tools", "Search", "search", "public");
......@@ -275,7 +306,7 @@ public class UserController {
node.addChild(new NavigationTreeNodeRO("user-data-profile", "Profile", "account_circle", "user-profile"));
node.addChild(new NavigationTreeNodeRO("user-data-access-token", "Access tokens", "key", "user-access-token"));
node.addChild(new NavigationTreeNodeRO("user-data-certificates", "Certificates", "article", "user-certificate"));
// node.addChild(new NavigationTreeNodeRO("user-data-membership", "Membership", "person", "user-membership"));
node.addChild(new NavigationTreeNodeRO("user-data-alert", "Alerts", "notifications", "user-alert"));
return node;
}
......
......@@ -21,16 +21,12 @@ package eu.europa.ec.edelivery.smp.ui.internal;
import eu.europa.ec.edelivery.smp.data.ui.AlertRO;
import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
import eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority;
import eu.europa.ec.edelivery.smp.logging.SMPLogger;
import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
import eu.europa.ec.edelivery.smp.services.ui.UIAlertService;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.*;
......@@ -50,9 +46,20 @@ public class AlertController {
this.uiAlertService = uiAlertService;
}
@GetMapping(produces = {MimeTypeUtils.APPLICATION_JSON_VALUE})
@Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN})
/**
* Method returns list of all alerts.
*
* @param userEncId - user id (encrypted) - used for authorization
* @param page - page number of the results to be returned.
* @param pageSize - number of results to be returned per page.
* @param orderBy - column name to order by (default: id)
* @param orderType - order type (default: desc)
* @return
*/
@GetMapping(path = "/{user-enc-id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
@PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator")
public ServiceResult<AlertRO> getAlertList(
@PathVariable("user-enc-id") String userEncId,
@RequestParam(value = PARAM_PAGINATION_PAGE, defaultValue = "0") int page,
@RequestParam(value = PARAM_PAGINATION_PAGE_SIZE, defaultValue = "10") int pageSize,
@RequestParam(value = PARAM_PAGINATION_ORDER_BY, defaultValue = "id", required = false) String orderBy,
......
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