Skip to content

Commit

Permalink
Closes Taskana#2563 - work in progress, frontend and TaskanaEngineCon…
Browse files Browse the repository at this point in the history
…troller(getCurrentUserInfo)
  • Loading branch information
MM1277 committed May 25, 2024
1 parent 5e7ca23 commit f294eef
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ void should_NotSetJaasSubject_When_AnnotationIsMissing_On_Test() {
void should_SetJaasSubject_When_AnnotationExists_On_Test() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo("user");
assertThat(CURRENT_USER_CONTEXT.getGroupIds()).isEmpty();
assertThat(CURRENT_USER_CONTEXT.getPermissionIds()).isEmpty();
}

@WithAccessId(
Expand All @@ -151,30 +150,6 @@ void should_SetJaasSubject_When_AnnotationExists_On_Test() {
void should_SetJaasSubjectWithGroups_When_AnnotationExistsWithGroups_On_Test() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo("user");
assertThat(CURRENT_USER_CONTEXT.getGroupIds()).containsExactlyInAnyOrder("group1", "group2");
assertThat(CURRENT_USER_CONTEXT.getPermissionIds()).isEmpty();
}

@WithAccessId(
user = "user",
permissions = {"permission1", "permission2"})
@Test
void should_SetJaasSubjectWithPermissions_When_AnnotationExistsWithPermissions_On_Test() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo("user");
assertThat(CURRENT_USER_CONTEXT.getGroupIds()).isEmpty();
assertThat(CURRENT_USER_CONTEXT.getPermissionIds())
.containsExactlyInAnyOrder("permission1", "permission2");
}

@WithAccessId(
user = "user",
groups = {"group1", "group2"},
permissions = {"permission1", "permission2"})
@Test
void should_SetJaasSubjectWithGroupsAndPerms_When_AnnotationExistsWithGroupsAndPerms_On_Test() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo("user");
assertThat(CURRENT_USER_CONTEXT.getGroupIds()).containsExactlyInAnyOrder("group1", "group2");
assertThat(CURRENT_USER_CONTEXT.getPermissionIds())
.containsExactlyInAnyOrder("permission1", "permission2");
}

@WithAccessId(user = "user")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ void should_GetAllTransferTargetsForSubjectUser_When_QueryingForMultiplePermissi
assertThat(results).hasSize(3);
}

@WithAccessId(user = "user-1-1", groups = GROUP_1_DN, permissions = PERM_1_DN)
@WithAccessId(user = "user-1-1", groups = {GROUP_1_DN, PERM_1_DN})
@Test
void should_GetAllTransferTargetsForSubjectUserGroupPerm_When_QueryingForSinglePermission() {
List<WorkbasketSummary> results =
Expand All @@ -242,7 +242,7 @@ void should_GetAllTransferTargetsForSubjectUserGroupPerm_When_QueryingForSingleP
assertThat(results).hasSize(7);
}

@WithAccessId(user = "user-1-1", groups = GROUP_1_DN, permissions = PERM_1_DN)
@WithAccessId(user = "user-1-1", groups = {GROUP_1_DN, PERM_1_DN})
@Test
void should_GetAllTransferTargetsForSubjectUserGroupPerm_When_QueryingForMultiplePermissions() {
List<WorkbasketSummary> results =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"EN": {
"workbaskets": {
"time": {
"debounceTime": 750
},
"information": {
"owner": {
"lookupField": true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;
import java.util.Map;
import javax.naming.InvalidNameException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.http.ResponseEntity;
Expand All @@ -15,6 +16,7 @@
import pro.taskana.common.api.ConfigurationService;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.api.security.CurrentUserContext;
import pro.taskana.common.rest.ldap.LdapClient;
import pro.taskana.common.rest.models.CustomAttributesRepresentationModel;
import pro.taskana.common.rest.models.TaskanaUserInfoRepresentationModel;
import pro.taskana.common.rest.models.VersionRepresentationModel;
Expand All @@ -28,17 +30,19 @@ public class TaskanaEngineController {
private final TaskanaEngine taskanaEngine;
private final CurrentUserContext currentUserContext;
private final ConfigurationService configurationService;
private final LdapClient ldapClient;

@Autowired
TaskanaEngineController(
TaskanaConfiguration taskanaConfiguration,
TaskanaEngine taskanaEngine,
CurrentUserContext currentUserContext,
ConfigurationService configurationService) {
ConfigurationService configurationService, LdapClient ldapClient) {
this.taskanaConfiguration = taskanaConfiguration;
this.taskanaEngine = taskanaEngine;
this.currentUserContext = currentUserContext;
this.configurationService = configurationService;
this.ldapClient = ldapClient;
}

/**
Expand Down Expand Up @@ -97,13 +101,18 @@ public ResponseEntity<Map<String, List<String>>> getClassificationCategoriesByTy
* This endpoint computes all information of the current user.
*
* @return the information of the current user.
* @throws InvalidNameException if the dn is invalid.
*/
@GetMapping(path = RestEndpoints.URL_CURRENT_USER)
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<TaskanaUserInfoRepresentationModel> getCurrentUserInfo() {
public ResponseEntity<TaskanaUserInfoRepresentationModel> getCurrentUserInfo()
throws InvalidNameException {
TaskanaUserInfoRepresentationModel resource = new TaskanaUserInfoRepresentationModel();
resource.setUserId(currentUserContext.getUserid());
resource.setGroupIds(currentUserContext.getGroupIds());
Map<String, List<String>> groupsAndPermissions =
ldapClient.searchAccessIdForGroupsAndPermissionsByDn(currentUserContext.getGroupIds());
resource.setPermissionIds(groupsAndPermissions.get("permissions"));
resource.setGroupIds(groupsAndPermissions.get("groups"));
taskanaConfiguration.getRoleMap().keySet().stream()
.filter(taskanaEngine::isUserInRole)
.forEach(resource.getRoles()::add);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -235,6 +237,29 @@ public List<AccessIdRepresentationModel> searchGroupsByName(final String name)
new GroupContextMapper());
}

public Map<String, List<String>> searchAccessIdForGroupsAndPermissionsByDn(List<String> dns)
throws InvalidNameException {
List<String> accessIdsOfGroupsAndPermissions = new ArrayList<>();
List<AccessIdRepresentationModel> permissions = new ArrayList<>();
List<String> accessIdsOfPermissions = new ArrayList<>();
for (String groupOrPermission : dns) {
accessIdsOfGroupsAndPermissions.add(searchAccessIdByDn(groupOrPermission)
.getAccessId());
}
for (String groupOrPermission : accessIdsOfGroupsAndPermissions) {
permissions.addAll(searchPermissionsByName(groupOrPermission));
}
for (AccessIdRepresentationModel permission : permissions) {
accessIdsOfPermissions.add(permission.getAccessId());
}
List<String> accessIdsOfGroups = new ArrayList<>(accessIdsOfGroupsAndPermissions);
accessIdsOfGroups.removeAll(accessIdsOfPermissions);
Map<String, List<String>> map = new HashMap<>();
map.put("permissions", accessIdsOfPermissions);
map.put("groups", accessIdsOfGroups);
return map;
}

public List<AccessIdRepresentationModel> searchPermissionsByName(final String name)
throws InvalidArgumentException {
isInitOrFail();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { TypeAheadComponent } from './type-ahead.component';
import { AccessIdsService } from '../../services/access-ids/access-ids.service';
import { of } from 'rxjs';
import { NgxsModule } from '@ngxs/store';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { HttpClient, HttpClientModule, HttpErrorResponse } from '@angular/common/http';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
Expand All @@ -19,6 +21,8 @@ describe('TypeAheadComponent with AccessId input', () => {
let fixture: ComponentFixture<TypeAheadComponent>;
let debugElement: DebugElement;
let component: TypeAheadComponent;
let httpClient: HttpClient;
let httpTestingController: HttpTestingController;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
Expand All @@ -30,7 +34,9 @@ describe('TypeAheadComponent with AccessId input', () => {
MatTooltipModule,
NoopAnimationsModule,
FormsModule,
ReactiveFormsModule
ReactiveFormsModule,
HttpClientModule,
HttpClientTestingModule
],
declarations: [TypeAheadComponent],
providers: [{ provide: AccessIdsService, useValue: accessIdService }]
Expand All @@ -40,6 +46,8 @@ describe('TypeAheadComponent with AccessId input', () => {
debugElement = fixture.debugElement;
component = fixture.componentInstance;
fixture.detectChanges();
httpClient = TestBed.get(HttpClient);
httpTestingController = TestBed.get(HttpTestingController);
}));

it('should create component', () => {
Expand Down
22 changes: 19 additions & 3 deletions web/src/app/shared/components/type-ahead/type-ahead.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, SimpleChange
import { AccessIdsService } from '../../services/access-ids/access-ids.service';
import { Observable, Subject } from 'rxjs';
import { FormControl, FormGroup } from '@angular/forms';
import { Customisation } from '../../../shared/models/customisation';
import { AccessId } from '../../models/access-id';
import { take, takeUntil, distinctUntilChanged, debounceTime } from 'rxjs/operators';
import { take, takeUntil, distinctUntilChanged, debounceTime, map } from 'rxjs/operators';
import { Select } from '@ngxs/store';
import { WorkbasketSelectors } from '../../store/workbasket-store/workbasket.selectors';
import { ButtonAction } from '../../../administration/models/button-action';
import { HttpClient } from '@angular/common/http';
const customisationUrl = 'environments/data-sources/taskana-customization.json';

@Component({
selector: 'taskana-shared-type-ahead',
Expand All @@ -30,13 +33,14 @@ export class TypeAheadComponent implements OnInit, OnDestroy {
name: string = '';
lastSavedAccessId: string = '';
filteredAccessIds: AccessId[] = [];
time: number;
destroy$ = new Subject<void>();
accessIdForm = new FormGroup({
accessId: new FormControl('')
});
emptyAccessId: AccessId = { accessId: '', name: '' };

constructor(private accessIdService: AccessIdsService) {}
constructor(private accessIdService: AccessIdsService, private httpClient: HttpClient) {}

ngOnChanges(changes: SimpleChanges) {
// currently needed because when saving, workbasket-details components sends old workbasket which reverts changes in this component
Expand All @@ -46,6 +50,16 @@ export class TypeAheadComponent implements OnInit, OnDestroy {
}

ngOnInit() {
this.httpClient
.get<Customisation>(customisationUrl)
.pipe(take(1))
.subscribe((customisation) => {
Object.keys(customisation).forEach((lang) => {
this.time = customisation[lang].workbaskets.time.debounceTime;
this.accessIdValueChanges();
});
});

if (this.isDisabled) {
this.accessIdForm.controls['accessId'].disable();
}
Expand All @@ -56,9 +70,11 @@ export class TypeAheadComponent implements OnInit, OnDestroy {
this.accessIdForm.controls['accessId'].setValue(this.lastSavedAccessId);
}
});
}

accessIdValueChanges() {
this.accessIdForm.controls['accessId'].valueChanges
.pipe(debounceTime(750), distinctUntilChanged(), takeUntil(this.destroy$))
.pipe(debounceTime(this.time), distinctUntilChanged(), takeUntil(this.destroy$))
.subscribe(() => {
const value = this.accessIdForm.controls['accessId'].value;
if (value === '') {
Expand Down
5 changes: 5 additions & 0 deletions web/src/app/shared/models/customisation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface ClassificationCategoryImages {

export interface WorkbasketsCustomisation {
information?: { owner: LookupField } & CustomFields;
time?: DebounceTime;
'access-items'?: AccessItemsCustomisation;
}

Expand All @@ -46,6 +47,10 @@ export interface LookupField {
lookupField: boolean;
}

export interface DebounceTime {
debounceTime: number;
}

export function getCustomFields(amount: number): OperatorFunction<CustomFields, CustomField[]> {
return map<CustomFields, CustomField[]>((customisation) =>
[...Array(amount).keys()]
Expand Down
3 changes: 3 additions & 0 deletions web/src/environments/data-sources/taskana-customization.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"EN": {
"workbaskets": {
"time": {
"debounceTime": 750
},
"information": {
"owner": {
"lookupField": true
Expand Down

0 comments on commit f294eef

Please sign in to comment.