From 8207aadde29797c8e79c9567e0dcb97219b67473 Mon Sep 17 00:00:00 2001 From: Miguel Martin Rojas Date: Tue, 3 Jul 2018 14:00:16 +0200 Subject: [PATCH] TSK-623 BUG link children classification correctly to it parent Link children classification to it corresponding parent in root domain when creating a new children classification in one specific domain. --- .../pro/taskana/impl/ClassificationImpl.java | 26 ++++++++++++ .../impl/ClassificationServiceImpl.java | 42 ++++++++++++------- .../impl/ClassificationServiceImplTest.java | 22 ++++++++++ .../rest/ClassificationControllerIntTest.java | 38 ++++++++++++++++- web/src/app/shared/tree/tree.component.ts | 13 ++++-- 5 files changed, 122 insertions(+), 19 deletions(-) diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationImpl.java index d3fc05ec2..5a62b7c4d 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationImpl.java @@ -37,6 +37,32 @@ public class ClassificationImpl implements Classification { ClassificationImpl() { } + ClassificationImpl(ClassificationImpl classification) { + this.id = classification.getId(); + this.key = classification.getKey(); + this.parentId = classification.getParentId(); + this.parentKey = classification.getParentKey(); + this.category = classification.getCategory(); + this.type = classification.getType(); + this.domain = classification.getDomain(); + this.isValidInDomain = classification.getIsValidInDomain(); + this.created = classification.getCreated(); + this.modified = classification.getModified(); + this.name = classification.getName(); + this.description = classification.getDescription(); + this.priority = classification.getPriority(); + this.serviceLevel = classification.getServiceLevel(); + this.applicationEntryPoint = classification.getApplicationEntryPoint(); + this.custom1 = classification.getCustom1(); + this.custom2 = classification.getCustom2(); + this.custom3 = classification.getCustom3(); + this.custom4 = classification.getCustom4(); + this.custom5 = classification.getCustom5(); + this.custom6 = classification.getCustom6(); + this.custom7 = classification.getCustom7(); + this.custom8 = classification.getCustom8(); + } + @Override public String getId() { return id; diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java index c16a9e3ca..33e49fcf8 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java @@ -126,38 +126,50 @@ public class ClassificationServiceImpl implements ClassificationService { private void addClassificationToRootDomain(ClassificationImpl classificationImpl) { if (!Objects.equals(classificationImpl.getDomain(), "")) { boolean doesExist = true; - String idBackup = classificationImpl.getId(); - String domainBackup = classificationImpl.getDomain(); - boolean isValidInDomainBackup = classificationImpl.getIsValidInDomain(); - classificationImpl.setId(IdGenerator.generateWithPrefix(ID_PREFIX_CLASSIFICATION)); - classificationImpl.setDomain(""); - classificationImpl.setIsValidInDomain(false); + ClassificationImpl rootClassification = new ClassificationImpl(classificationImpl); + rootClassification.setId(IdGenerator.generateWithPrefix(ID_PREFIX_CLASSIFICATION)); + rootClassification.setParentId(getClassificationRootDomainParentId(classificationImpl)); + rootClassification.setDomain(""); + rootClassification.setIsValidInDomain(false); try { - this.getClassification(classificationImpl.getKey(), classificationImpl.getDomain()); - throw new ClassificationAlreadyExistException(classificationImpl); + this.getClassification(rootClassification.getKey(), rootClassification.getDomain()); + throw new ClassificationAlreadyExistException(rootClassification); } catch (ClassificationNotFoundException e) { doesExist = false; LOGGER.debug( "Method createClassification: Classification does not exist in root domain. Classification {}.", - classificationImpl); + rootClassification); } catch (ClassificationAlreadyExistException ex) { LOGGER.warn( "Method createClassification: Classification does already exist in root domain. Classification {}.", - classificationImpl); + rootClassification); } finally { if (!doesExist) { - classificationMapper.insert(classificationImpl); + classificationMapper.insert(rootClassification); LOGGER.debug( "Method createClassification: Classification created in root-domain, too. Classification {}.", - classificationImpl); + rootClassification); } - classificationImpl.setId(idBackup); - classificationImpl.setDomain(domainBackup); - classificationImpl.setIsValidInDomain(isValidInDomainBackup); } } } + private String getClassificationRootDomainParentId(ClassificationImpl classificationImpl) { + String rootParentId = ""; + try { + if (classificationImpl.getParentId() != null && !"".equals(classificationImpl.getParentId())) { + rootParentId = this.getClassification(this.getClassification(classificationImpl.getParentId()).getKey(), + "") + .getId(); + } + } catch (ClassificationNotFoundException e) { + LOGGER.warn( + "Method getRootDomainParentIdClassification: Cannot find parent classification in Root domain. Classification {}.", + classificationImpl); + } + return rootParentId; + } + @Override public Classification updateClassification(Classification classification) throws NotAuthorizedException, ConcurrencyException, ClassificationNotFoundException, InvalidArgumentException { diff --git a/lib/taskana-core/src/test/java/pro/taskana/impl/ClassificationServiceImplTest.java b/lib/taskana-core/src/test/java/pro/taskana/impl/ClassificationServiceImplTest.java index ab40431a4..e2598d872 100644 --- a/lib/taskana-core/src/test/java/pro/taskana/impl/ClassificationServiceImplTest.java +++ b/lib/taskana-core/src/test/java/pro/taskana/impl/ClassificationServiceImplTest.java @@ -201,6 +201,28 @@ public class ClassificationServiceImplTest { assertThat(classification.getKey(), equalTo(key)); } + @Test + public void testCreateChildClassificationInOwnDomainAndCopyInRootDomain() + throws ClassificationAlreadyExistException, NotAuthorizedException, DomainNotFoundException, + InvalidArgumentException { + Classification classification = createDummyClassification(""); + classification.setParentId("parentId"); + ClassificationImpl parentRootClassification = (ClassificationImpl) createDummyClassification("ParentIdRoot"); + parentRootClassification.setKey("ParentKey"); + parentRootClassification.setDomain(""); + doReturn(null).when(classificationMapperMock).findByKeyAndDomain(classification.getKey(), + classification.getDomain()); + doReturn(null).when(classificationMapperMock).findByKeyAndDomain(classification.getKey(), ""); + doReturn(parentRootClassification).when(classificationMapperMock).findByKeyAndDomain("ParentKey", ""); + + doReturn(parentRootClassification).when(classificationMapperMock).findById("parentId"); + doReturn(true).when(taskanaEngineImplMock).domainExists(any()); + + cutSpy.createClassification(classification); + + verify(classificationMapperMock, times(1)).findByKeyAndDomain("ParentKey", ""); + } + @Test public void testCreateClassificationIntoRootDomain() throws ClassificationAlreadyExistException, NotAuthorizedException, diff --git a/rest/taskana-rest-spring-example/src/test/java/pro/taskana/rest/ClassificationControllerIntTest.java b/rest/taskana-rest-spring-example/src/test/java/pro/taskana/rest/ClassificationControllerIntTest.java index 1936f66fb..9a57483cc 100644 --- a/rest/taskana-rest-spring-example/src/test/java/pro/taskana/rest/ClassificationControllerIntTest.java +++ b/rest/taskana-rest-spring-example/src/test/java/pro/taskana/rest/ClassificationControllerIntTest.java @@ -217,6 +217,42 @@ public class ClassificationControllerIntTest { con.disconnect(); } + @Test + public void testCreateClassificationWithParentKeyInDOMAIN_AShouldCreateAClassificationInRootDomain() + throws IOException { + String newClassification = "{\"classificationId\":\"\",\"category\":\"MANUAL\",\"domain\":\"DOMAIN_A\",\"key\":\"NEW_CLASS_P2\",\"name\":\"new classification\",\"type\":\"TASK\",\"parentKey\":\"T2100\"}"; + + URL url = new URL(server + port + "/v1/classifications"); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("POST"); + con.setRequestProperty("Authorization", "Basic dGVhbWxlYWRfMTp0ZWFtbGVhZF8x"); + con.setDoOutput(true); + con.setRequestProperty("Content-Type", "application/json"); + BufferedWriter out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream())); + out.write(newClassification); + out.flush(); + out.close(); + assertEquals(201, con.getResponseCode()); + con.disconnect(); + + ResponseEntity> response = template.exchange( + server + port + "/v1/classifications", HttpMethod.GET, + request, + new ParameterizedTypeReference>() { + + }); + assertNotNull(response.getBody().getLink(Link.REL_SELF)); + boolean foundClassificationCreated = false; + for (ClassificationSummaryResource classification : response.getBody().getContent()) { + if ("NEW_CLASS_P2".equals(classification.getKey()) && "".equals(classification.getDomain()) + && "T2100".equals(classification.getParentKey())) { + foundClassificationCreated = true; + } + } + + assertEquals(true, foundClassificationCreated); + } + @Test public void testReturn400IfCreateClassificationWithIncompatibleParentIdAndKey() throws IOException { String newClassification = "{\"classificationId\":\"\",\"category\":\"MANUAL\",\"domain\":\"DOMAIN_B\",\"key\":\"NEW_CLASS_P3\",\"name\":\"new classification\",\"type\":\"TASK\",\"parentId\":\"CLI:200000000000000000000000000000000015\",\"parentKey\":\"T2000\"}"; @@ -433,7 +469,7 @@ public class ClassificationControllerIntTest { converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json")); converter.setObjectMapper(mapper); - RestTemplate template = new RestTemplate(Collections.> singletonList(converter)); + RestTemplate template = new RestTemplate(Collections.>singletonList(converter)); return template; } diff --git a/web/src/app/shared/tree/tree.component.ts b/web/src/app/shared/tree/tree.component.ts index fcac152fa..65f2c5d00 100644 --- a/web/src/app/shared/tree/tree.component.ts +++ b/web/src/app/shared/tree/tree.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, Input, Output, EventEmitter, ViewChild, AfterViewChecked, OnChanges, SimpleChanges } from '@angular/core'; +import { Component, OnInit, Input, Output, EventEmitter, ViewChild, AfterViewChecked, OnDestroy } from '@angular/core'; import { TreeNodeModel } from 'app/models/tree-node'; import { KEYS, ITreeOptions, TreeComponent, TreeNode } from 'angular-tree-component'; @@ -7,13 +7,14 @@ import { ClassificationCategoriesService } from 'app/administration/services/classification-categories-service/classification-categories.service'; import { Pair } from 'app/models/pair'; +import { Subscription } from 'rxjs/Subscription'; @Component({ selector: 'taskana-tree', templateUrl: './tree.component.html', styleUrls: ['./tree.component.scss'] }) -export class TaskanaTreeComponent implements OnInit, AfterViewChecked { +export class TaskanaTreeComponent implements OnInit, AfterViewChecked, OnDestroy { @ViewChild('tree') @@ -29,6 +30,7 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked { private filterTextOld: string private filterIconOld: string + private removedNodeIdSubscription: Subscription; options: ITreeOptions = { displayField: 'name', @@ -48,7 +50,7 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked { constructor(private treeService: TreeService, private categoryService: ClassificationCategoriesService) { } ngOnInit() { - this.treeService.getRemovedNodeId().subscribe(value => { + this.removedNodeIdSubscription = this.treeService.getRemovedNodeId().subscribe(value => { const removedNode = this.getNode(value); if (removedNode.parent) { removedNode.parent.collapse(); @@ -135,5 +137,10 @@ export class TaskanaTreeComponent implements OnInit, AfterViewChecked { this.tree.treeModel.collapseAll(); } } + + ngOnDestroy(): void { + if (this.removedNodeIdSubscription) { this.removedNodeIdSubscription.unsubscribe() } + } + }