diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java index 81d99e966..9ef25393f 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java @@ -1,6 +1,7 @@ package dev.dsf.fhir.authorization; import java.sql.Connection; +import java.sql.SQLException; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; @@ -8,6 +9,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import org.hl7.fhir.r4.model.Questionnaire; import org.hl7.fhir.r4.model.QuestionnaireResponse; import org.hl7.fhir.r4.model.QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent; import org.hl7.fhir.r4.model.QuestionnaireResponse.QuestionnaireResponseItemComponent; @@ -87,6 +89,13 @@ private Optional newResourceOk(QuestionnaireResponse newResource, getItemAndValidate(newResource, CODESYSTEM_DSF_BPMN_USER_TASK_VALUE_USER_TASK_ID, errors); + String questionnaireUrlAndVersion = newResource.getQuestionnaire(); + if (!questionnaireExists(questionnaireUrlAndVersion)) + { + errors.add( + "Questionnaire ressource referenced via canonical QuestionnaireResponse.questionnaire does not exist"); + } + if (errors.isEmpty()) return Optional.empty(); else @@ -140,6 +149,23 @@ private Optional getItemAndValidate(QuestionnaireResponse newResource, S return Optional.of(value.getValue()); } + private boolean questionnaireExists(String questionnaireUrlAndVersion) + { + try + { + Optional questionnaire = daoProvider.getQuestionnaireDao() + .readByUrlAndVersion(questionnaireUrlAndVersion); + + return questionnaire.isPresent(); + } + catch (SQLException e) + { + logger.warn("Could not check questionnaire with url|version '{}' for questionnaire-response - {}", + questionnaireUrlAndVersion, e.getMessage()); + throw new RuntimeException(e); + } + } + @Override public Optional reasonReadAllowed(Connection connection, Identity identity, QuestionnaireResponse existingResource) @@ -228,7 +254,16 @@ private boolean modificationsOk(QuestionnaireResponse oldResource, Questionnaire "Modifications only allowed if item.answer with linkId '{}' not changed, change from '{}' to '{}' not allowed", CODESYSTEM_DSF_BPMN_USER_TASK_VALUE_BUSINESS_KEY, oldUserTaskId, newUserTaskId); - return statusModificationOk && userTaskIdOk && businesssKeyOk; + String oldQuestionnaireUrlAndVersion = oldResource.getQuestionnaire(); + String newQuestionnaireUrlAndVersion = newResource.getQuestionnaire(); + boolean questionnaireCanonicalOk = oldResource.hasQuestionnaire() && newResource.hasQuestionnaire() + && oldQuestionnaireUrlAndVersion.equals(newQuestionnaireUrlAndVersion); + + if (!questionnaireCanonicalOk) + logger.warn("Modifications of QuestionnaireResponse.questionnaire not allowed, changed from '{}' to '{}'", + oldQuestionnaireUrlAndVersion, newQuestionnaireUrlAndVersion); + + return statusModificationOk && userTaskIdOk && businesssKeyOk && questionnaireCanonicalOk; } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ValidationSupportWithFetchFromDb.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ValidationSupportWithFetchFromDb.java index 7f3362aa6..363c66c24 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ValidationSupportWithFetchFromDb.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ValidationSupportWithFetchFromDb.java @@ -13,6 +13,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.Measure; +import org.hl7.fhir.r4.model.Questionnaire; import org.hl7.fhir.r4.model.StructureDefinition; import org.hl7.fhir.r4.model.ValueSet; import org.slf4j.Logger; @@ -23,6 +24,7 @@ import ca.uhn.fhir.context.support.IValidationSupport; import dev.dsf.fhir.dao.CodeSystemDao; import dev.dsf.fhir.dao.MeasureDao; +import dev.dsf.fhir.dao.QuestionnaireDao; import dev.dsf.fhir.dao.StructureDefinitionDao; import dev.dsf.fhir.dao.ValueSetDao; import dev.dsf.fhir.function.SupplierWithSqlException; @@ -38,10 +40,11 @@ public class ValidationSupportWithFetchFromDb implements IValidationSupport, Ini private final CodeSystemDao codeSystemDao; private final ValueSetDao valueSetDao; private final MeasureDao measureDao; + private final QuestionnaireDao questionnaireDao; public ValidationSupportWithFetchFromDb(FhirContext context, StructureDefinitionDao structureDefinitionDao, StructureDefinitionDao structureDefinitionSnapshotDao, CodeSystemDao codeSystemDao, ValueSetDao valueSetDao, - MeasureDao measureDao) + MeasureDao measureDao, QuestionnaireDao questionnaireDao) { this.context = context; @@ -50,6 +53,7 @@ public ValidationSupportWithFetchFromDb(FhirContext context, StructureDefinition this.codeSystemDao = codeSystemDao; this.valueSetDao = valueSetDao; this.measureDao = measureDao; + this.questionnaireDao = questionnaireDao; } @Override @@ -59,6 +63,8 @@ public void afterPropertiesSet() throws Exception Objects.requireNonNull(structureDefinitionSnapshotDao, "structureDefinitionSnapshotDao"); Objects.requireNonNull(codeSystemDao, "codeSystemDao"); Objects.requireNonNull(valueSetDao, "valueSetDao"); + Objects.requireNonNull(measureDao, "measureDao"); + Objects.requireNonNull(questionnaireDao, "questionnaireDao"); } @Override @@ -102,6 +108,11 @@ public T fetchResource(Class theClass, String theUr return theClass.cast(fetchMeasure(theUri)); } + if (Questionnaire.class.equals(theClass)) + { + return theClass.cast(fetchQuestionnaire(theUri)); + } + return null; } @@ -163,4 +174,10 @@ public Measure fetchMeasure(String url) else return null; } + + public Questionnaire fetchQuestionnaire(String url) + { + Optional questionnaire = throwRuntimeException(() -> questionnaireDao.readByUrlAndVersion(url)); + return questionnaire.orElse(null); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ValidationSupportWithFetchFromDbWithTransaction.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ValidationSupportWithFetchFromDbWithTransaction.java index 8f6dff4fb..2c18306e5 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ValidationSupportWithFetchFromDbWithTransaction.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ValidationSupportWithFetchFromDbWithTransaction.java @@ -13,6 +13,8 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.Measure; +import org.hl7.fhir.r4.model.Questionnaire; import org.hl7.fhir.r4.model.StructureDefinition; import org.hl7.fhir.r4.model.ValueSet; import org.slf4j.Logger; @@ -22,6 +24,8 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.support.IValidationSupport; import dev.dsf.fhir.dao.CodeSystemDao; +import dev.dsf.fhir.dao.MeasureDao; +import dev.dsf.fhir.dao.QuestionnaireDao; import dev.dsf.fhir.dao.StructureDefinitionDao; import dev.dsf.fhir.dao.ValueSetDao; import dev.dsf.fhir.function.SupplierWithSqlException; @@ -36,12 +40,15 @@ public class ValidationSupportWithFetchFromDbWithTransaction implements IValidat private final StructureDefinitionDao structureDefinitionSnapshotDao; private final CodeSystemDao codeSystemDao; private final ValueSetDao valueSetDao; + private final MeasureDao measureDao; + private final QuestionnaireDao questionnaireDao; private final Connection connection; public ValidationSupportWithFetchFromDbWithTransaction(FhirContext context, StructureDefinitionDao structureDefinitionDao, StructureDefinitionDao structureDefinitionSnapshotDao, - CodeSystemDao codeSystemDao, ValueSetDao valueSetDao, Connection connection) + CodeSystemDao codeSystemDao, ValueSetDao valueSetDao, MeasureDao measureDao, + QuestionnaireDao questionnaireDao, Connection connection) { this.context = context; @@ -49,6 +56,8 @@ public ValidationSupportWithFetchFromDbWithTransaction(FhirContext context, this.structureDefinitionSnapshotDao = structureDefinitionSnapshotDao; this.codeSystemDao = codeSystemDao; this.valueSetDao = valueSetDao; + this.measureDao = measureDao; + this.questionnaireDao = questionnaireDao; this.connection = connection; } @@ -91,6 +100,28 @@ public List fetchAllStructureDefinitions() return new ArrayList<>(byUrl.values()); } + @Override + public T fetchResource(Class theClass, String theUri) + { + T resource = IValidationSupport.super.fetchResource(theClass, theUri); + if (resource != null) + { + return resource; + } + + if (Measure.class.equals(theClass)) + { + return theClass.cast(fetchMeasure(theUri)); + } + + if (Questionnaire.class.equals(theClass)) + { + return theClass.cast(fetchQuestionnaire(theUri)); + } + + return null; + } + @Override public StructureDefinition fetchStructureDefinition(String url) { @@ -144,4 +175,19 @@ public ValueSet fetchValueSet(String url) else return null; } + + public Measure fetchMeasure(String url) + { + Optional measure = throwRuntimeException(() -> measureDao.readByUrlAndVersion(url)); + if (measure.isPresent()) + return measure.get(); + else + return null; + } + + public Questionnaire fetchQuestionnaire(String url) + { + Optional questionnaire = throwRuntimeException(() -> questionnaireDao.readByUrlAndVersion(url)); + return questionnaire.orElse(null); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/ValidationConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/ValidationConfig.java index 44e434d6a..c9db6a986 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/ValidationConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/ValidationConfig.java @@ -39,7 +39,8 @@ public IValidationSupport validationSupport() return new ValidationSupportWithCache(fhirConfig.fhirContext(), validationSupportChain(new ValidationSupportWithFetchFromDb(fhirConfig.fhirContext(), daoConfig.structureDefinitionDao(), daoConfig.structureDefinitionSnapshotDao(), - daoConfig.codeSystemDao(), daoConfig.valueSetDao(), daoConfig.measureDao()))); + daoConfig.codeSystemDao(), daoConfig.valueSetDao(), daoConfig.measureDao(), + daoConfig.questionnaireDao()))); } private ValidationSupportChain validationSupportChain(IValidationSupport dbSupport) @@ -71,7 +72,8 @@ public IValidationSupport validationSupportWithTransaction(Connection connection ValidationSupportWithCache validationSupport = new ValidationSupportWithCache(fhirConfig.fhirContext(), validationSupportChain(new ValidationSupportWithFetchFromDbWithTransaction(fhirConfig.fhirContext(), daoConfig.structureDefinitionDao(), daoConfig.structureDefinitionSnapshotDao(), - daoConfig.codeSystemDao(), daoConfig.valueSetDao(), connection))); + daoConfig.codeSystemDao(), daoConfig.valueSetDao(), daoConfig.measureDao(), + daoConfig.questionnaireDao(), connection))); return validationSupport.populateCache(validationSupport().fetchAllConformanceResources()); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/static/bookmarks.js b/dsf-fhir/dsf-fhir-server/src/main/resources/static/bookmarks.js index 204375847..b82794697 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/static/bookmarks.js +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/static/bookmarks.js @@ -1,102 +1,102 @@ function showBookmarks() { - const bookmarks = document.getElementById('bookmarks'); - bookmarks.style.display = 'block'; + const bookmarks = document.getElementById('bookmarks') + bookmarks.style.display = 'block' const click = e => { if (!bookmarks.contains(e.target) && !document.getElementById('bookmark-list').contains(e.target)) { - closeBookmarks(); - document.removeEventListener('click', click); + closeBookmarks() + document.removeEventListener('click', click) } - }; - document.addEventListener('click', click); + } + document.addEventListener('click', click) } function closeBookmarks() { - checkBookmarked(); - createBookmarkList(getBookmarks()); + checkBookmarked() + createBookmarkList(getBookmarks()) - const bookmarks = document.getElementById('bookmarks'); - bookmarks.style.display = 'none'; + const bookmarks = document.getElementById('bookmarks') + bookmarks.style.display = 'none' } function addCurrentBookmark() { - const addIcon = document.getElementById('bookmark-add'); - addIcon.style.display = 'none'; - const removeIcon = document.getElementById('bookmark-remove'); - removeIcon.style.display = 'inline'; + const addIcon = document.getElementById('bookmark-add') + addIcon.style.display = 'none' + const removeIcon = document.getElementById('bookmark-remove') + removeIcon.style.display = 'inline' - const url = window.location.pathname.substring(new URL(document.head.baseURI).pathname.length) + window.location.search; - const resourceType = getResourceTypeOrMisc(url); + const url = window.location.pathname.substring(new URL(document.head.baseURI).pathname.length) + window.location.search + const resourceType = getResourceTypeOrMisc(url) - const bookmarks = getBookmarks(); + const bookmarks = getBookmarks() - const resourceTypeBookmarks = bookmarks[resourceType] !== undefined ? bookmarks[resourceType] : []; - resourceTypeBookmarks.push(url); - bookmarks[resourceType] = resourceTypeBookmarks.sort(); + const resourceTypeBookmarks = bookmarks[resourceType] !== undefined ? bookmarks[resourceType] : [] + resourceTypeBookmarks.push(url) + bookmarks[resourceType] = resourceTypeBookmarks.sort() - saveBookmarks(bookmarks); - createBookmarkList(bookmarks); + saveBookmarks(bookmarks) + createBookmarkList(bookmarks) } function removeCurrentBookmark() { - const addIcon = document.getElementById('bookmark-add'); - addIcon.style.display = 'inline'; - const removeIcon = document.getElementById('bookmark-remove'); - removeIcon.style.display = 'none'; + const addIcon = document.getElementById('bookmark-add') + addIcon.style.display = 'inline' + const removeIcon = document.getElementById('bookmark-remove') + removeIcon.style.display = 'none' - const url = window.location.pathname.substring(new URL(document.head.baseURI).pathname.length) + window.location.search; - const resourceType = getResourceTypeOrMisc(url); + const url = window.location.pathname.substring(new URL(document.head.baseURI).pathname.length) + window.location.search + const resourceType = getResourceTypeOrMisc(url) - const bookmarks = getBookmarks(); + const bookmarks = getBookmarks() - const resourceTypeBookmarks = bookmarks[resourceType] !== undefined ? bookmarks[resourceType] : []; - bookmarks[resourceType] = resourceTypeBookmarks.filter(item => item !== url).sort(); + const resourceTypeBookmarks = bookmarks[resourceType] !== undefined ? bookmarks[resourceType] : [] + bookmarks[resourceType] = resourceTypeBookmarks.filter(item => item !== url).sort() - saveBookmarks(bookmarks); - createBookmarkList(bookmarks); + saveBookmarks(bookmarks) + createBookmarkList(bookmarks) } function checkBookmarked() { - const url = window.location.pathname.substring(new URL(document.head.baseURI).pathname.length) + window.location.search; - const resourceType = getResourceTypeOrMisc(url); + const url = window.location.pathname.substring(new URL(document.head.baseURI).pathname.length) + window.location.search + const resourceType = getResourceTypeOrMisc(url) - const addIcon = document.getElementById('bookmark-add'); - const removeIcon = document.getElementById('bookmark-remove'); + const addIcon = document.getElementById('bookmark-add') + const removeIcon = document.getElementById('bookmark-remove') - const bookmarks = getBookmarks(); + const bookmarks = getBookmarks() if (bookmarks[resourceType] !== undefined && bookmarks[resourceType].includes(url)) { - addIcon.style.display = "none"; - removeIcon.style.display = "inline"; + addIcon.style.display = "none" + removeIcon.style.display = "inline" } else { - addIcon.style.display = "inline"; - removeIcon.style.display = "none"; + addIcon.style.display = "inline" + removeIcon.style.display = "none" } - createBookmarkList(bookmarks); + createBookmarkList(bookmarks) } function getBookmarks() { if (localStorage != null) { - return localStorage.getItem('bookmarks') != null && localStorage.getItem('bookmarks') != "" ? cleanBookmarkUrls(JSON.parse(localStorage.getItem('bookmarks'))) : getInitialBookmarks(); + return localStorage.getItem('bookmarks') != null && localStorage.getItem('bookmarks') != "" ? cleanBookmarkUrls(JSON.parse(localStorage.getItem('bookmarks'))) : getInitialBookmarks() } else { - alert("session storage not available"); + alert("session storage not available") } } function cleanBookmarkUrls(bookmarks) { - let b = new Object(); - Object.entries(bookmarks).map(e => new Array(e[0], e[1].map(u => u.startsWith('/fhir/') ? u.substring('/fhir/'.length) : u))).forEach(e => b[e[0]] = e[1]); - return b; + let b = new Object() + Object.entries(bookmarks).map(e => new Array(e[0], e[1].map(u => u.startsWith('/fhir/') ? u.substring('/fhir/'.length) : u))).forEach(e => b[e[0]] = e[1]) + return b } function saveBookmarks(bookmarks) { if (localStorage != null) { - localStorage.setItem('bookmarks', JSON.stringify(bookmarks)); + localStorage.setItem('bookmarks', JSON.stringify(bookmarks)) } else { - alert("session storage not available"); + alert("session storage not available") } } @@ -115,12 +115,12 @@ function getResourceTypeOrMisc(url) { + '|ResearchElementDefinition|ResearchStudy|ResearchSubject|RiskAssessment|RiskEvidenceSynthesis|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|StructureDefinition' + '|StructureMap|Subscription|Substance|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|SubstanceReferenceInformation|SubstanceSourceMaterial|SubstanceSpecification|SupplyDelivery' + '|SupplyRequest|Task|TerminologyCapabilities|TestReport|TestScript|ValueSet|VerificationResult|VisionPrescription)' - + '(?:[\/?#](?:.*)?)?$'); - const match = regex.exec(url); + + '(?:[\/?#](?:.*)?)?$') + const match = regex.exec(url) if (match != null) - return match[1]; + return match[1] else - return '_misc'; + return '_misc' } function getBasePath() { @@ -140,93 +140,93 @@ function getInitialBookmarks() { 'Subscription': ['Subscription'], 'Task': ['Task', 'Task?_sort=-_lastUpdated', 'Task?_sort=_profile,identifier&status=draft'], 'ValueSet': ['ValueSet'] - }; + } } function createBookmarkList(bookmarks) { - let counter = 1; - const addIcon = document.getElementById('bookmark-add'); - const removeIcon = document.getElementById('bookmark-remove'); - const bookmarkList = document.getElementById('bookmarks-list'); - bookmarkList.innerHTML = null; + let counter = 1 + const addIcon = document.getElementById('bookmark-add') + const removeIcon = document.getElementById('bookmark-remove') + const bookmarkList = document.getElementById('bookmarks-list') + bookmarkList.innerHTML = null Object.entries(bookmarks).sort((e1, e2) => e1[0].localeCompare(e2[0])).forEach(e => { if (e[0] !== '_misc' && e[1].length > 0) { - const h4 = document.createElement("h4"); - const h4Link = document.createElement("a"); - h4Link.href = e[0]; - h4Link.title = 'Open ' + e[0]; - const h4Content = document.createTextNode(e[0]); - h4.appendChild(h4Link); - h4Link.appendChild(h4Content); - bookmarkList.appendChild(h4); + const h4 = document.createElement("h4") + const h4Link = document.createElement("a") + h4Link.href = e[0] + h4Link.title = 'Open ' + e[0] + const h4Content = document.createTextNode(e[0]) + h4.appendChild(h4Link) + h4Link.appendChild(h4Content) + bookmarkList.appendChild(h4) } if (e[1].length > 0) { e[1].filter(b => b !== e[0]).forEach(b => { - const c = counter; - const div = document.createElement("div"); - div.setAttribute('id', 'bookmarks-list-entry-' + c); - const divAddIcon = addIcon.cloneNode(true); - divAddIcon.setAttribute('id', 'bookmark-add-' + c); - divAddIcon.addEventListener('click', () => addBookmark(b, c)); - divAddIcon.setAttribute('viewBox', '4 0 24 24'); - divAddIcon.style.display = 'none'; - divAddIcon.children[0].innerHTML = 'Add Bookmark: ' + b; - const divRemoveIcon = removeIcon.cloneNode(true); - divRemoveIcon.setAttribute('id', 'bookmark-remove-' + c); - divRemoveIcon.addEventListener('click', () => removeBookmark(b, c)); - divRemoveIcon.setAttribute('viewBox', '4 0 24 24'); - divRemoveIcon.style.display = 'inline'; - divRemoveIcon.children[0].innerHTML = 'Remove Bookmark: ' + b; - const divLink = document.createElement("a"); - divLink.href = b; - divLink.title = 'Open ' + b; - const divContent = document.createTextNode(e[0] === '_misc' ? b : b.substring(e[0].length)); - div.appendChild(divAddIcon); - div.appendChild(divRemoveIcon); - div.appendChild(divLink); - divLink.appendChild(divContent); - bookmarkList.appendChild(div); - - counter++; - }); + const c = counter + const div = document.createElement("div") + div.setAttribute('id', 'bookmarks-list-entry-' + c) + const divAddIcon = addIcon.cloneNode(true) + divAddIcon.setAttribute('id', 'bookmark-add-' + c) + divAddIcon.addEventListener('click', () => addBookmark(b, c)) + divAddIcon.setAttribute('viewBox', '4 0 24 24') + divAddIcon.style.display = 'none' + divAddIcon.children[0].innerHTML = 'Add Bookmark: ' + b + const divRemoveIcon = removeIcon.cloneNode(true) + divRemoveIcon.setAttribute('id', 'bookmark-remove-' + c) + divRemoveIcon.addEventListener('click', () => removeBookmark(b, c)) + divRemoveIcon.setAttribute('viewBox', '4 0 24 24') + divRemoveIcon.style.display = 'inline' + divRemoveIcon.children[0].innerHTML = 'Remove Bookmark: ' + b + const divLink = document.createElement("a") + divLink.href = b + divLink.title = 'Open ' + b + const divContent = document.createTextNode(e[0] === '_misc' ? b : b.substring(e[0].length)) + div.appendChild(divAddIcon) + div.appendChild(divRemoveIcon) + div.appendChild(divLink) + divLink.appendChild(divContent) + bookmarkList.appendChild(div) + + counter++ + }) } - }); + }) } function removeBookmark(url, counter) { - const addIcon = document.getElementById('bookmark-add-' + counter); - addIcon.style.display = 'inline'; - const removeIcon = document.getElementById('bookmark-remove-' + counter); - removeIcon.style.display = 'none'; - const div = document.getElementById('bookmarks-list-entry-' + counter); - div.className = 'bookmarks-list-entry-removed'; + const addIcon = document.getElementById('bookmark-add-' + counter) + addIcon.style.display = 'inline' + const removeIcon = document.getElementById('bookmark-remove-' + counter) + removeIcon.style.display = 'none' + const div = document.getElementById('bookmarks-list-entry-' + counter) + div.className = 'bookmarks-list-entry-removed' - const resourceType = getResourceTypeOrMisc(url); + const resourceType = getResourceTypeOrMisc(url) - const bookmarks = getBookmarks(); + const bookmarks = getBookmarks() - const resourceTypeBookmarks = bookmarks[resourceType] !== undefined ? bookmarks[resourceType] : []; - bookmarks[resourceType] = resourceTypeBookmarks.filter(item => item !== url).sort(); + const resourceTypeBookmarks = bookmarks[resourceType] !== undefined ? bookmarks[resourceType] : [] + bookmarks[resourceType] = resourceTypeBookmarks.filter(item => item !== url).sort() - saveBookmarks(bookmarks); + saveBookmarks(bookmarks) } function addBookmark(url, counter) { - const addIcon = document.getElementById('bookmark-add-' + counter); - addIcon.style.display = 'none'; - const removeIcon = document.getElementById('bookmark-remove-' + counter); - removeIcon.style.display = 'inline'; - const div = document.getElementById('bookmarks-list-entry-' + counter); - div.className = null; + const addIcon = document.getElementById('bookmark-add-' + counter) + addIcon.style.display = 'none' + const removeIcon = document.getElementById('bookmark-remove-' + counter) + removeIcon.style.display = 'inline' + const div = document.getElementById('bookmarks-list-entry-' + counter) + div.className = null - const resourceType = getResourceTypeOrMisc(url); + const resourceType = getResourceTypeOrMisc(url) - const bookmarks = getBookmarks(); + const bookmarks = getBookmarks() - let resourceTypeBookmarks = bookmarks[resourceType] !== undefined ? bookmarks[resourceType] : []; - resourceTypeBookmarks.push(url); - bookmarks[resourceType] = resourceTypeBookmarks.sort(); + let resourceTypeBookmarks = bookmarks[resourceType] !== undefined ? bookmarks[resourceType] : [] + resourceTypeBookmarks.push(url) + bookmarks[resourceType] = resourceTypeBookmarks.sort() - saveBookmarks(bookmarks); + saveBookmarks(bookmarks) } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/static/dsf.css b/dsf-fhir/dsf-fhir-server/src/main/resources/static/dsf.css index a35313ec4..0e532750f 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/static/dsf.css +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/static/dsf.css @@ -332,7 +332,7 @@ pre.lang-html { } .bundle>#header>table { - width: 100% + width: 100% } .bundle>#header>table td:nth-child(2) { @@ -361,7 +361,7 @@ pre.lang-html { .bundle>#list>table { border-collapse: separate; border-spacing: 0 1rem; - width: 100% + width: 100% } .bundle>#list>table tr:not(:first-child) { @@ -495,42 +495,42 @@ pre.lang-html { } .resource { - border: 1px solid #ccc; - padding: 20px 20px 10px 20px; - color: var(--color-prime); + border: 1px solid #ccc; + padding: 20px 20px 10px 20px; + color: var(--color-prime); } .meta { - display: flex; - flex-direction: row + display: flex; + flex-direction: row } .row-list { - padding-inline-start: 25px; - margin-top: 0.15em; - margin-bottom: 0.1em; + padding-inline-start: 25px; + margin-top: 0.15em; + margin-bottom: 0.1em; } .row-text>a { - text-decoration: none; - color: var(--color-disabled-text); + text-decoration: none; + color: var(--color-disabled-text); } .row-text>a:hover { - text-decoration: underline; + text-decoration: underline; } .row-text, .row-text>a:visited { - color: var(--color-disabled-text); - word-wrap: break-word; + color: var(--color-disabled-text); + word-wrap: break-word; } .row-text.id-value { - font-family: monospace; + font-family: monospace; } div.row-text { - padding-left: 6px; + padding-left: 6px; } .row[active="true"] { @@ -570,42 +570,42 @@ div.row-text { } .flex-element { - display: flex; - flex-direction: row; + display: flex; + flex-direction: row; } .flex-element-100 { - width: 100%; - margin-right: 0em; + width: 100%; + margin-right: 0em; } .flex-element-67 { - width: 67%; + width: 67%; } .flex-element-50 { - width: 50%; - margin-right: 0em; + width: 50%; + margin-right: 0em; } .flex-element-33 { - width: 33%; + width: 33%; } .flex-element-margin { - margin-right: 0.7em; + margin-right: 0.7em; } .authorization { - padding-bottom: 0.25em !important; + padding-bottom: 0.25em !important; } .authorization>h3 { - margin-top: 0; - margin-bottom: 0; - padding: 1em 1em 0.75em 0.25em; - font-size: 1em; + margin-top: 0; + margin-bottom: 0; + padding: 1em 1em 0.75em 0.25em; + font-size: 1em; } @media print { diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/static/form.css b/dsf-fhir/dsf-fhir-server/src/main/resources/static/form.css index 7ebcca221..270ed0966 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/static/form.css +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/static/form.css @@ -34,7 +34,7 @@ fieldset#form-fieldset { } .row-extension-0 > .input-group { - padding-right: 1em; + padding-right: 1em; } .row-label-extension-no-value { diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/static/form.js b/dsf-fhir/dsf-fhir-server/src/main/resources/static/form.js index f40e958b2..d6f8732ab 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/static/form.js +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/static/form.js @@ -382,9 +382,7 @@ function disableSpinner() { spinner.classList.add("spinner-disabled") } -function adaptTaskFormInputs() { - const resourceType = getResourceTypeForCurrentUrl(); - +function adaptTaskFormInputs(resourceType) { if (resourceType !== null && resourceType[1] !== undefined && resourceType[1] === 'Task') { const task = getResourceAsJson() @@ -394,12 +392,32 @@ function adaptTaskFormInputs() { let currentUrl = window.location.origin + window.location.pathname let requestUrl = currentUrl.slice(0, currentUrl.indexOf("/Task")) + "/StructureDefinition?url=" + profile - loadStructureDefinition(requestUrl).then(bundle => parseStructureDefinition(bundle)) + loadResource(requestUrl).then(bundle => parseStructureDefinition(bundle)) } } } -function loadStructureDefinition(url) { +function adaptQuestionnaireResponseInputsIfNotVersion1_0_0(resourceType) { + if (resourceType !== null && resourceType[1] !== undefined && resourceType[1] === 'QuestionnaireResponse') { + const questionnaireResponse = getResourceAsJson() + + if (questionnaireResponse.status === 'in-progress' && questionnaireResponse.questionnaire !== null) { + const urlVersion = questionnaireResponse.questionnaire.split('|') + + if (urlVersion.length > 1) { + const url = urlVersion[0] + const version = urlVersion[1] + + let currentUrl = window.location.origin + window.location.pathname + let requestUrl = currentUrl.slice(0, currentUrl.indexOf("/QuestionnaireResponse")) + "/Questionnaire?url=" + url + '&version=' + version + + loadResource(requestUrl).then(bundle => parseQuestionnaire(bundle)) + } + } + } +} + +function loadResource(url) { return fetch(url, { method: "GET", headers: { @@ -409,17 +427,37 @@ function loadStructureDefinition(url) { } function parseStructureDefinition(bundle) { - if (bundle.entry.length > 0 && bundle.entry[0].resource != null) { + if (bundle.entry.length > 0 && bundle.entry[0].resource !== null) { const structureDefinition = bundle.entry[0].resource - if (structureDefinition.differential != null) { + if (structureDefinition.differential !== null) { const differentials = structureDefinition.differential.element const slices = filterInputSlices(differentials) const groupedSlices = groupBy(slices, d => d.id.split(".")[1]) const definitions = getDefinitions(groupedSlices) const indices = new Map() - definitions.forEach(definition => { modifyInputRow(definition, indices) }) + definitions.forEach(definition => { modifyTaskInputRow(definition, indices) }) + } + } +} + +function parseQuestionnaire(bundle) { + if (bundle.entry.length > 0 && bundle.entry[0].resource !== null) { + const questionnaire = bundle.entry[0].resource + + if (questionnaire.meta !== null && questionnaire.meta.profile !== null && questionnaire.meta.profile.length > 0) { + const profile = questionnaire.meta.profile[0] + const urlVersion = profile.split('|') + + if (urlVersion.length > 1) { + const url = urlVersion[0] + const version = urlVersion[1] + + if (version !== '1.0.0' && questionnaire.item !== undefined) { + questionnaire.item.forEach(item => { modifyQuestionnaireInputRow(item) }) + } + } } } } @@ -434,7 +472,7 @@ function groupBy(list, keyGetter) { const map = new Map() list.forEach((item) => { - const key = keyGetter(item); + const key = keyGetter(item) const collection = map.get(key) if (!collection) { @@ -442,9 +480,9 @@ function groupBy(list, keyGetter) { } else { collection.push(item) } - }); + }) - return Array.from(map.values()); + return Array.from(map.values()) } function getDefinitions(groupedSlices) { @@ -455,7 +493,7 @@ function getDefinitions(groupedSlices) { identifier: window.location.href, typeSystem: getValueOfDifferential(differentials, "Task.input.type.coding.system", "fixedUri"), typeCode: getValueOfDifferential(differentials, "Task.input.type.coding.code", "fixedCode"), - valueType: (valueType != undefined && valueType.length > 0) ? valueType[0].code : undefined, + valueType: (valueType !== undefined && valueType.length > 0) ? valueType[0].code : undefined, min: getValueOfDifferential(differentials, "Task.input", "min"), max: getValueOfDifferential(differentials, "Task.input", "max"), } @@ -472,7 +510,7 @@ function getValueOfDifferential(differentials, path, property) { } } -function modifyInputRow(definition, indices) { +function modifyTaskInputRow(definition, indices) { const row = document.querySelector("[name='" + definition.typeCode + "-input-row']") if (row) { @@ -484,7 +522,7 @@ function modifyInputRow(definition, indices) { const label = row.querySelector("label") if (label) { - const cardinalities = htmlToElement('', " [" + definition.min + ".." + definition.max + "]") + const cardinalities = htmlToElement('', ' [' + definition.min + '..' + definition.max + ']') label.appendChild(cardinalities) if (definition.max !== "1") { @@ -505,8 +543,28 @@ function modifyInputRow(definition, indices) { } } +function modifyQuestionnaireInputRow(item) { + const row = document.querySelector("[name='" + item.linkId + "-input-row']") + + if (row) { + if (item.required !== true) { + row.setAttribute("optional", "") + } + + const label = row.querySelector("label") + if (label) { + const cardinalities = htmlToElement('', ' [' + (item.required === true ? '1': '0') + '..1]') + label.appendChild(cardinalities) + } + } + + if (item.item) { + item.item.forEach(item => { modifyQuestionnaireInputRow(item) }) + } +} + function appendInputRowAfter(inputRow, definition, indices) { - const clone = inputRow.cloneNode(true); + const clone = inputRow.cloneNode(true) const index = getIndex(getDefinitionId(definition), indices) clone.setAttribute("index", index) diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/static/help.js b/dsf-fhir/dsf-fhir-server/src/main/resources/static/help.js index ea37e559a..ba30f9299 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/static/help.js +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/static/help.js @@ -1,105 +1,97 @@ function showHelp() { - const httpRequest = new XMLHttpRequest(); + const httpRequest = new XMLHttpRequest() if (httpRequest != null) { - httpRequest.onreadystatechange = () => createAndShowHelp(httpRequest); - httpRequest.open('GET', document.head.baseURI + 'metadata'); - httpRequest.setRequestHeader('Accept', 'application/fhir+json'); - httpRequest.send(); + httpRequest.onreadystatechange = () => createAndShowHelp(httpRequest) + httpRequest.open('GET', document.head.baseURI + 'metadata') + httpRequest.setRequestHeader('Accept', 'application/fhir+json') + httpRequest.send() } else { - createAndShowHelp(null); + createAndShowHelp(null) } } function closeHelp() { - const help = document.getElementById('help'); - help.style.display = 'none'; + const help = document.getElementById('help') + help.style.display = 'none' } function createAndShowHelp(httpRequest) { if (httpRequest != null && httpRequest.readyState === XMLHttpRequest.DONE) { if (httpRequest.status === 200) { - const metadata = JSON.parse(httpRequest.responseText); - const resourceType = getResourceTypeForCurrentUrl(); + const metadata = JSON.parse(httpRequest.responseText) + const resourceType = getResourceTypeForCurrentUrl() /* /, /metadata, /_history */ if (resourceType == null) { - const searchParam = metadata.rest[0].resource[0].searchParam; + const searchParam = metadata.rest[0].resource[0].searchParam if (window.location.pathname.endsWith('/metadata')) { - createHelp(searchParam.filter(p => ['_format', '_pretty', '_summary'].includes(p.name))); + createHelp(searchParam.filter(p => ['_format', '_pretty', '_summary'].includes(p.name))) } else if (window.location.pathname.endsWith('/_history')) { - createHelp(searchParam.filter(p => ['_count', '_format', '_page', '_pretty', '_summary', '_at', '_since'].includes(p.name))); + createHelp(searchParam.filter(p => ['_count', '_format', '_page', '_pretty', '_summary', '_at', '_since'].includes(p.name))) } else { - createHelp(searchParam.filter(p => ['_format', '_pretty', '_summary'].includes(p.name))); + createHelp(searchParam.filter(p => ['_format', '_pretty', '_summary'].includes(p.name))) } } else { - const searchParam = metadata.rest[0].resource.filter(r => r.type === resourceType[1])[0].searchParam; + const searchParam = metadata.rest[0].resource.filter(r => r.type === resourceType[1])[0].searchParam //Resource if (resourceType[1] !== undefined && resourceType[2] === undefined && resourceType[3] === undefined && resourceType[4] === undefined) { - createHelp(searchParam.filter(p => !['_at', '_since'].includes(p.name))); + createHelp(searchParam.filter(p => !['_at', '_since'].includes(p.name))) } //Resource/_history else if (resourceType[1] !== undefined && resourceType[2] === undefined && resourceType[3] !== undefined && resourceType[4] === undefined) { - createHelp(searchParam.filter(p => ['_count', '_format', '_page', '_pretty', '_summary', '_at', '_since'].includes(p.name))); + createHelp(searchParam.filter(p => ['_count', '_format', '_page', '_pretty', '_summary', '_at', '_since'].includes(p.name))) } //Resource/id else if (resourceType[1] !== undefined && resourceType[2] !== undefined && resourceType[3] === undefined && resourceType[4] === undefined) { - createHelp(searchParam.filter(p => ['_format', '_pretty', '_summary'].includes(p.name))); + createHelp(searchParam.filter(p => ['_format', '_pretty', '_summary'].includes(p.name))) } //Resource/id/_history else if (resourceType[1] !== undefined && resourceType[2] !== undefined && resourceType[3] !== undefined && resourceType[4] === undefined) { - createHelp(searchParam.filter(p => ['_count', '_format', '_page', '_pretty', '_summary', '_at', '_since'].includes(p.name))); + createHelp(searchParam.filter(p => ['_count', '_format', '_page', '_pretty', '_summary', '_at', '_since'].includes(p.name))) } //Resource/id/_history/version else if (resourceType[1] !== undefined && resourceType[2] !== undefined && resourceType[3] !== undefined && resourceType[4] !== undefined) { - createHelp(searchParam.filter(p => ['_format', '_pretty', '_summary'].includes(p.name))); + createHelp(searchParam.filter(p => ['_format', '_pretty', '_summary'].includes(p.name))) } } } } - const help = document.getElementById('help'); - help.style.display = 'block'; + const help = document.getElementById('help') + help.style.display = 'block' const click = e => { if (!help.contains(e.target) && !document.getElementById('help-icon').contains(e.target)) { - closeHelp(); - document.removeEventListener('click', click); + closeHelp() + document.removeEventListener('click', click) } - }; - document.addEventListener('click', click); -} - -function getResourceTypeForCurrentUrl() { - const url = window.location.pathname; - const regex = new RegExp('^(?:(?:[A-Za-z0-9\-\\\.\:\%\$]*\/)+)?' - + '(Account|ActivityDefinition|AdverseEvent|AllergyIntolerance|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BiologicallyDerivedProduct|BodyStructure|Bundle|CapabilityStatement|CarePlan|CareTeam|CatalogEntry|ChargeItem|ChargeItemDefinition|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition|Consent|Contract|Coverage|CoverageEligibilityRequest|CoverageEligibilityResponse|DetectedIssue|Device|DeviceDefinition|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EffectEvidenceSynthesis|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|EventDefinition|Evidence|EvidenceVariable|ExampleScenario|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingStudy|Immunization|ImmunizationEvaluation|ImmunizationRecommendation|ImplementationGuide|InsurancePlan|Invoice|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationKnowledge|MedicationRequest|MedicationStatement|MedicinalProduct|MedicinalProductAuthorization|MedicinalProductContraindication|MedicinalProductIndication|MedicinalProductIngredient|MedicinalProductInteraction|MedicinalProductManufactured|MedicinalProductPackaged|MedicinalProductPharmaceutical|MedicinalProductUndesirableEffect|MessageDefinition|MessageHeader|MolecularSequence|NamingSystem|NutritionOrder|Observation|ObservationDefinition|OperationDefinition|OperationOutcome|Organization|OrganizationAffiliation|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|Provenance|Questionnaire|QuestionnaireResponse|RelatedPerson|RequestGroup|ResearchDefinition|ResearchElementDefinition|ResearchStudy|ResearchSubject|RiskAssessment|RiskEvidenceSynthesis|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|StructureDefinition|StructureMap|Subscription|Substance|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|SubstanceReferenceInformation|SubstanceSourceMaterial|SubstanceSpecification|SupplyDelivery|SupplyRequest|Task|TerminologyCapabilities|TestReport|TestScript|ValueSet|VerificationResult|VisionPrescription)' - + '(\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})?(\/_history)?(\/[0-9]+)?(?:|\\?.*)$'); - return regex.exec(url); + } + document.addEventListener('click', click) } function createHelp(searchParam) { - const helpList = document.getElementById('help-list'); - helpList.innerHTML = null; + const helpList = document.getElementById('help-list') + helpList.innerHTML = null - for (let i = 0; i < searchParam.length; i++) { + for (let i = 0 i < searchParam.length i++) { const param = searchParam[i] - const div = document.createElement("div"); - const span1 = document.createElement("span"); - const span2 = document.createElement("span"); - const p = document.createElement("p"); + const div = document.createElement("div") + const span1 = document.createElement("span") + const span2 = document.createElement("span") + const p = document.createElement("p") - div.appendChild(span1); - div.appendChild(span2); - div.appendChild(p); - helpList.appendChild(div); + div.appendChild(span1) + div.appendChild(span2) + div.appendChild(p) + helpList.appendChild(div) - div.setAttribute('class', 'help-param'); - span1.innerText = param.name; - span1.setAttribute('class', 'help-param-name'); - span2.innerText = param.type; - span2.setAttribute('class', 'help-param-type'); - p.innerText = param.documentation; - p.setAttribute('class', 'help-param-documentation'); + div.setAttribute('class', 'help-param') + span1.innerText = param.name + span1.setAttribute('class', 'help-param-name') + span2.innerText = param.type + span2.setAttribute('class', 'help-param-type') + p.innerText = param.documentation + p.setAttribute('class', 'help-param-documentation') } } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/static/main.js b/dsf-fhir/dsf-fhir-server/src/main/resources/static/main.js index 0b9974efd..974f2b416 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/static/main.js +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/static/main.js @@ -1,24 +1,24 @@ function setUiTheme(theme = getUiTheme()) { - if (theme === 'dark') { - document.getElementById('light-mode').style.display = 'block' - document.getElementById('dark-mode').style.display = 'none' - } - else { - document.getElementById('light-mode').style.display = 'none' - document.getElementById('dark-mode').style.display = 'block' - } - - document.querySelector("html").setAttribute("theme", theme); - localStorage.setItem("theme", theme); + if (theme === 'dark') { + document.getElementById('light-mode').style.display = 'block' + document.getElementById('dark-mode').style.display = 'none' + } + else { + document.getElementById('light-mode').style.display = 'none' + document.getElementById('dark-mode').style.display = 'block' + } + + document.querySelector("html").setAttribute("theme", theme) + localStorage.setItem("theme", theme) } function getUiTheme() { - if (localStorage !== null && localStorage.getItem("theme") !== null) - return localStorage.getItem("theme") - else if (window.matchMedia("(prefers-color-scheme: dark)").matches) - return "dark" - else - return "light" + if (localStorage !== null && localStorage.getItem("theme") !== null) + return localStorage.getItem("theme") + else if (window.matchMedia("(prefers-color-scheme: dark)").matches) + return "dark" + else + return "light" } window.addEventListener('DOMContentLoaded', () => { @@ -26,7 +26,10 @@ window.addEventListener('DOMContentLoaded', () => { prettyPrint() checkBookmarked() openInitialTab() - adaptTaskFormInputs() + + const resourceType = getResourceTypeForCurrentUrl() + adaptTaskFormInputs(resourceType) + adaptQuestionnaireResponseInputsIfNotVersion1_0_0(resourceType) document.querySelector('div#icons > svg#help-icon')?.addEventListener('click', () => showHelp()) document.querySelector('div#icons > svg#light-mode')?.addEventListener('click', () => setUiTheme('light')) @@ -42,10 +45,9 @@ window.addEventListener('DOMContentLoaded', () => { document.querySelector('div.tab > button#json-button')?.addEventListener('click', () => openTab('json')) document.querySelector('div.tab > button#xml-button')?.addEventListener('click', () => openTab('xml')) - const resourceType = getResourceTypeForCurrentUrl(); + const resourceType = getResourceTypeForCurrentUrl() if (resourceType != null && resourceType[1] != null && resourceType[2] === undefined && resourceType[3] === undefined && resourceType[4] === undefined) { - // search bundle rows document.querySelectorAll('div#html > div.bundle > div#list td.id-value:first-child').forEach(td => { if (td?.firstChild?.href) { @@ -57,9 +59,7 @@ window.addEventListener('DOMContentLoaded', () => { }) } - if (resourceType != null && resourceType[1] === 'QuestionnaireResponse' && resourceType[2] !== null) { - // input placeholder insert buttons document.querySelectorAll('form > fieldset#form-fieldset > div.row input').forEach(input => { if (input?.nextElementSibling?.tagName?.toLowerCase() === 'svg') { @@ -77,7 +77,6 @@ window.addEventListener('DOMContentLoaded', () => { } if (resourceType != null && resourceType[1] === 'Task' && resourceType[2] !== null) { - // input placeholder insert buttons document.querySelectorAll('form > fieldset#form-fieldset > section#inputs > div.row input').forEach(input => { if (input?.nextElementSibling?.tagName?.toLowerCase() === 'svg') { diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/static/tabs.js b/dsf-fhir/dsf-fhir-server/src/main/resources/static/tabs.js index 4d6dfeb0d..c2d69296d 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/static/tabs.js +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/static/tabs.js @@ -1,71 +1,71 @@ function openTab(lang) { - const tabcontent = document.getElementsByClassName("prettyprint") - for (let i = 0; i < tabcontent.length; i++) - tabcontent[i].style.display = "none" + const tabcontent = document.getElementsByClassName("prettyprint") + for (let i = 0 i < tabcontent.length i++) + tabcontent[i].style.display = "none" - const tablinks = document.getElementsByClassName("tablinks") - for (let i = 0; i < tablinks.length; i++) - tablinks[i].className = tablinks[i].className.replace(" active", "") + const tablinks = document.getElementsByClassName("tablinks") + for (let i = 0 i < tablinks.length i++) + tablinks[i].className = tablinks[i].className.replace(" active", "") - document.getElementById(lang).style.display = "block" - document.getElementById(lang + "-button").className += " active" + document.getElementById(lang).style.display = "block" + document.getElementById(lang + "-button").className += " active" - if (lang != "html" && localStorage != null) - localStorage.setItem('lang', lang) - - if (lang == "html") - lang = localStorage != null && localStorage.getItem("lang") != null ? localStorage.getItem("lang") : "xml" + if (lang != "html" && localStorage != null) + localStorage.setItem('lang', lang) - setDownloadLink(lang) + if (lang == "html") + lang = localStorage != null && localStorage.getItem("lang") != null ? localStorage.getItem("lang") : "xml" + + setDownloadLink(lang) } function openInitialTab() { - if (document.querySelector('div#html') != null) - openTab("html") - else { - const lang = localStorage != null && localStorage.getItem("lang") != null ? localStorage.getItem("lang") : "xml" - if (lang == "xml" || lang == "json") - openTab(lang); - } + if (document.querySelector('div#html') != null) + openTab("html") + else { + const lang = localStorage != null && localStorage.getItem("lang") != null ? localStorage.getItem("lang") : "xml" + if (lang == "xml" || lang == "json") + openTab(lang) + } } function setDownloadLink(lang) { - const searchParams = new URLSearchParams(document.location.search) - searchParams.set('_format', lang) - searchParams.set('_pretty', 'true') + const searchParams = new URLSearchParams(document.location.search) + searchParams.set('_format', lang) + searchParams.set('_pretty', 'true') - const downloadLink = document.getElementById('download-link') - downloadLink.href = '?' + searchParams.toString() - downloadLink.download = getDownloadFileName(lang) - downloadLink.title = 'Download as ' + lang.toUpperCase() + const downloadLink = document.getElementById('download-link') + downloadLink.href = '?' + searchParams.toString() + downloadLink.download = getDownloadFileName(lang) + downloadLink.title = 'Download as ' + lang.toUpperCase() } function getDownloadFileName(lang) { - const resourceType = getResourceTypeForCurrentUrl() + const resourceType = getResourceTypeForCurrentUrl() - /* /, /metadata, /_history */ - if (resourceType == null) { - if (window.location.pathname.endsWith('/metadata')) - return "metadata." + lang - else if (window.location.pathname.endsWith('/_history')) - return "history." + lang - else - return "root." + lang - } else { - //Resource - if (resourceType[1] !== undefined && resourceType[2] === undefined && resourceType[3] === undefined && resourceType[4] === undefined) - return resourceType[1] + '_Search.' + lang - //Resource/_history - else if (resourceType[1] !== undefined && resourceType[2] === undefined && resourceType[3] !== undefined && resourceType[4] === undefined) - return resourceType[1] + '_History.' + lang - //Resource/id - else if (resourceType[1] !== undefined && resourceType[2] !== undefined && resourceType[3] === undefined && resourceType[4] === undefined) - return resourceType[1] + '_' + resourceType[2].replace('/', '') + '.' + lang - //Resource/id/_history - else if (resourceType[1] !== undefined && resourceType[2] !== undefined && resourceType[3] !== undefined && resourceType[4] === undefined) - return resourceType[1] + '_' + resourceType[2].replace('/', '') + '_History.' + lang - //Resource/id/_history/version - else if (resourceType[1] !== undefined && resourceType[2] !== undefined && resourceType[3] !== undefined && resourceType[4] !== undefined) - return resourceType[1] + '_' + resourceType[2].replace('/', '') + '_v' + resourceType[4].replace('/', '') + '.' + lang - } + /* /, /metadata, /_history */ + if (resourceType == null) { + if (window.location.pathname.endsWith('/metadata')) + return "metadata." + lang + else if (window.location.pathname.endsWith('/_history')) + return "history." + lang + else + return "root." + lang + } else { + //Resource + if (resourceType[1] !== undefined && resourceType[2] === undefined && resourceType[3] === undefined && resourceType[4] === undefined) + return resourceType[1] + '_Search.' + lang + //Resource/_history + else if (resourceType[1] !== undefined && resourceType[2] === undefined && resourceType[3] !== undefined && resourceType[4] === undefined) + return resourceType[1] + '_History.' + lang + //Resource/id + else if (resourceType[1] !== undefined && resourceType[2] !== undefined && resourceType[3] === undefined && resourceType[4] === undefined) + return resourceType[1] + '_' + resourceType[2].replace('/', '') + '.' + lang + //Resource/id/_history + else if (resourceType[1] !== undefined && resourceType[2] !== undefined && resourceType[3] !== undefined && resourceType[4] === undefined) + return resourceType[1] + '_' + resourceType[2].replace('/', '') + '_History.' + lang + //Resource/id/_history/version + else if (resourceType[1] !== undefined && resourceType[2] !== undefined && resourceType[3] !== undefined && resourceType[4] !== undefined) + return resourceType[1] + '_' + resourceType[2].replace('/', '') + '_v' + resourceType[4].replace('/', '') + '.' + lang + } } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/static/util.js b/dsf-fhir/dsf-fhir-server/src/main/resources/static/util.js index 3793d3f24..9a5d36846 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/static/util.js +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/static/util.js @@ -1,11 +1,12 @@ function getResourceTypeForCurrentUrl() { - const url = window.location.pathname; - const regex = new RegExp('(?:(?:[A-Za-z0-9\-\\\.\:\%\$]*\/)+)?' - + '(Account|ActivityDefinition|AdverseEvent|AllergyIntolerance|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BiologicallyDerivedProduct|BodyStructure|Bundle|CapabilityStatement|CarePlan|CareTeam|CatalogEntry|ChargeItem|ChargeItemDefinition|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition|Consent|Contract|Coverage|CoverageEligibilityRequest|CoverageEligibilityResponse|DetectedIssue|Device|DeviceDefinition|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EffectEvidenceSynthesis|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|EventDefinition|Evidence|EvidenceVariable|ExampleScenario|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingStudy|Immunization|ImmunizationEvaluation|ImmunizationRecommendation|ImplementationGuide|InsurancePlan|Invoice|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationKnowledge|MedicationRequest|MedicationStatement|MedicinalProduct|MedicinalProductAuthorization|MedicinalProductContraindication|MedicinalProductIndication|MedicinalProductIngredient|MedicinalProductInteraction|MedicinalProductManufactured|MedicinalProductPackaged|MedicinalProductPharmaceutical|MedicinalProductUndesirableEffect|MessageDefinition|MessageHeader|MolecularSequence|NamingSystem|NutritionOrder|Observation|ObservationDefinition|OperationDefinition|OperationOutcome|Organization|OrganizationAffiliation|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|Provenance|Questionnaire|QuestionnaireResponse|RelatedPerson|RequestGroup|ResearchDefinition|ResearchElementDefinition|ResearchStudy|ResearchSubject|RiskAssessment|RiskEvidenceSynthesis|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|StructureDefinition|StructureMap|Subscription|Substance|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|SubstanceReferenceInformation|SubstanceSourceMaterial|SubstanceSpecification|SupplyDelivery|SupplyRequest|Task|TerminologyCapabilities|TestReport|TestScript|ValueSet|VerificationResult|VisionPrescription)' - + '(?:(?:\/([A-Za-z0-9\-\.]{1,64}))?(?:\/(_history)(?:\/([0-9]{1,64}))?)?)?(?:\\?.*)?$'); - const match = regex.exec(url); - if (match != null) - return match; - else - return null; + const url = window.location.pathname + const regex = new RegExp('(?:(?:[A-Za-z0-9\-\\\.\:\%\$]*\/)+)?' + + '(Account|ActivityDefinition|AdverseEvent|AllergyIntolerance|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BiologicallyDerivedProduct|BodyStructure|Bundle|CapabilityStatement|CarePlan|CareTeam|CatalogEntry|ChargeItem|ChargeItemDefinition|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition|Consent|Contract|Coverage|CoverageEligibilityRequest|CoverageEligibilityResponse|DetectedIssue|Device|DeviceDefinition|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EffectEvidenceSynthesis|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|EventDefinition|Evidence|EvidenceVariable|ExampleScenario|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingStudy|Immunization|ImmunizationEvaluation|ImmunizationRecommendation|ImplementationGuide|InsurancePlan|Invoice|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationKnowledge|MedicationRequest|MedicationStatement|MedicinalProduct|MedicinalProductAuthorization|MedicinalProductContraindication|MedicinalProductIndication|MedicinalProductIngredient|MedicinalProductInteraction|MedicinalProductManufactured|MedicinalProductPackaged|MedicinalProductPharmaceutical|MedicinalProductUndesirableEffect|MessageDefinition|MessageHeader|MolecularSequence|NamingSystem|NutritionOrder|Observation|ObservationDefinition|OperationDefinition|OperationOutcome|Organization|OrganizationAffiliation|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|Provenance|Questionnaire|QuestionnaireResponse|RelatedPerson|RequestGroup|ResearchDefinition|ResearchElementDefinition|ResearchStudy|ResearchSubject|RiskAssessment|RiskEvidenceSynthesis|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|StructureDefinition|StructureMap|Subscription|Substance|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|SubstanceReferenceInformation|SubstanceSourceMaterial|SubstanceSpecification|SupplyDelivery|SupplyRequest|Task|TerminologyCapabilities|TestReport|TestScript|ValueSet|VerificationResult|VisionPrescription)' + + '(?:(?:\/([A-Za-z0-9\-\.]{1,64}))?(?:\/(_history)(?:\/([0-9]{1,64}))?)?)?(?:\\?.*)?$') + + const match = regex.exec(url) + if (match != null) + return match + else + return null } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractQuestionnaireIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractQuestionnaireIntegrationTest.java new file mode 100644 index 000000000..22c55dde2 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractQuestionnaireIntegrationTest.java @@ -0,0 +1,144 @@ +package dev.dsf.fhir.integration; + +import static org.junit.Assert.assertNotNull; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.hl7.fhir.r4.model.CanonicalType; +import org.hl7.fhir.r4.model.Enumerations; +import org.hl7.fhir.r4.model.Meta; +import org.hl7.fhir.r4.model.Organization; +import org.hl7.fhir.r4.model.Questionnaire; +import org.hl7.fhir.r4.model.QuestionnaireResponse; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.ResourceType; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.Type; + +import dev.dsf.fhir.authentication.OrganizationProvider; + +public class AbstractQuestionnaireIntegrationTest extends AbstractIntegrationTest +{ + protected static final String QUESTIONNAIRE_URL = "http://dsf.dev/fhir/Questionnaire/userTask/foo"; + protected static final String QUESTIONNAIRE_VERSION = "1.0.0"; + protected static final String QUESTIONNAIRE_URL_VERSION = QUESTIONNAIRE_URL + "|" + QUESTIONNAIRE_VERSION; + protected static final String TEST_IDENTIFIER_SYSTEM = "http://dsf.dev/fhir/CodeSystem/test"; + protected static final String TEST_IDENTIFIER_VALUE = "foo"; + protected static final Enumerations.PublicationStatus QUESTIONNAIRE_STATUS = Enumerations.PublicationStatus.ACTIVE; + protected static final Date QUESTIONNAIRE_DATE = Date + .from(LocalDateTime.parse("2022-01-01T00:00:00").toInstant(ZoneOffset.UTC)); + protected static final String QUESTIONNAIRE_ITEM_USER_TASK_ID_LINK = "user-task-id"; + protected static final String QUESTIONNAIRE_ITEM_USER_TASK_ID_TEXT = "The user-task-id of the process execution"; + protected static final String QUESTIONNAIRE_ITEM_BUSINESS_KEY_LINK = "business-key"; + protected static final String QUESTIONNAIRE_ITEM_BUSINESS_KEY_TEXT = "The business-key of the process execution"; + + protected static final QuestionnaireResponse.QuestionnaireResponseStatus QUESTIONNAIRE_RESPONSE_STATUS = QuestionnaireResponse.QuestionnaireResponseStatus.INPROGRESS; + protected static final Date QUESTIONNAIRE_RESPONSE_DATE = Date + .from(LocalDateTime.parse("2022-01-02T00:00:00").toInstant(ZoneOffset.UTC)); + + protected Questionnaire createQuestionnaireProfileVersion100() + { + Questionnaire questionnaire = new Questionnaire(); + questionnaire.getMeta().addProfile("http://dsf.dev/fhir/StructureDefinition/questionnaire|1.0.0"); + questionnaire.getMeta().addTag().setSystem("http://dsf.dev/fhir/CodeSystem/read-access-tag").setCode("ALL"); + + questionnaire.setUrl(QUESTIONNAIRE_URL); + questionnaire.setVersion(QUESTIONNAIRE_VERSION); + + questionnaire.addIdentifier().setSystem(TEST_IDENTIFIER_SYSTEM).setValue(TEST_IDENTIFIER_VALUE); + + questionnaire.setStatus(QUESTIONNAIRE_STATUS); + questionnaire.setDate(QUESTIONNAIRE_DATE); + + questionnaire.addItem().setLinkId(QUESTIONNAIRE_ITEM_USER_TASK_ID_LINK) + .setText(QUESTIONNAIRE_ITEM_USER_TASK_ID_TEXT).setType(Questionnaire.QuestionnaireItemType.STRING); + questionnaire.addItem().setLinkId(QUESTIONNAIRE_ITEM_BUSINESS_KEY_LINK) + .setText(QUESTIONNAIRE_ITEM_BUSINESS_KEY_TEXT).setType(Questionnaire.QuestionnaireItemType.STRING); + + return questionnaire; + } + + protected Questionnaire createQuestionnaireProfileVersion100(String questionnaireVersion) + { + Questionnaire questionnaire = createQuestionnaireProfileVersion100(); + return questionnaire.setVersion(questionnaireVersion); + } + + protected Questionnaire createQuestionnaireProfileVersion150() + { + Questionnaire questionnaire = createQuestionnaireProfileVersion100(); + Meta meta = questionnaire.getMeta(); + + String profile = meta.getProfile().get(0).getValue().replace("1.0.0", "1.5.0"); + meta.setProfile(List.of(new CanonicalType(profile))); + + questionnaire.getItem().forEach(i -> i.setRequired(true)); + + return questionnaire; + } + + protected Questionnaire createQuestionnaireProfileVersion150(String questionnaireVersion) + { + Questionnaire questionnaire = createQuestionnaireProfileVersion150(); + return questionnaire.setVersion(questionnaireVersion); + } + + protected void addItem(Questionnaire questionnaire, String linkId, String text, + Questionnaire.QuestionnaireItemType type, Optional required) + { + Questionnaire.QuestionnaireItemComponent item = questionnaire.addItem().setLinkId(linkId).setText(text) + .setType(type); + required.ifPresent(item::setRequired); + } + + protected QuestionnaireResponse createQuestionnaireResponse() + { + OrganizationProvider organizationProvider = getSpringWebApplicationContext() + .getBean(OrganizationProvider.class); + assertNotNull(organizationProvider); + + QuestionnaireResponse questionnaireResponse = new QuestionnaireResponse(); + questionnaireResponse.getMeta() + .addProfile("http://dsf.dev/fhir/StructureDefinition/questionnaire-response|1.0.0"); + + questionnaireResponse.getIdentifier().setSystem(TEST_IDENTIFIER_SYSTEM).setValue(TEST_IDENTIFIER_VALUE); + questionnaireResponse.setQuestionnaire(QUESTIONNAIRE_URL_VERSION); + + questionnaireResponse.setStatus(QUESTIONNAIRE_RESPONSE_STATUS); + questionnaireResponse.setAuthored(QUESTIONNAIRE_RESPONSE_DATE); + + Organization localOrganization = organizationProvider.getLocalOrganization().get(); + questionnaireResponse.setSubject(new Reference("Organization/" + localOrganization.getIdElement().getIdPart())); + questionnaireResponse.setAuthor(new Reference().setType(ResourceType.Organization.name()) + .setIdentifier(localOrganization.getIdentifierFirstRep())); + + addItem(questionnaireResponse, QUESTIONNAIRE_ITEM_USER_TASK_ID_LINK, QUESTIONNAIRE_ITEM_USER_TASK_ID_TEXT, + new StringType(UUID.randomUUID().toString())); + addItem(questionnaireResponse, QUESTIONNAIRE_ITEM_BUSINESS_KEY_LINK, QUESTIONNAIRE_ITEM_BUSINESS_KEY_TEXT, + new StringType(UUID.randomUUID().toString())); + + return questionnaireResponse; + } + + protected QuestionnaireResponse createQuestionnaireResponse(String questionnaireVersion) + { + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); + String urlVersion = questionnaireResponse.getQuestionnaire().replace(QUESTIONNAIRE_VERSION, + questionnaireVersion); + return questionnaireResponse.setQuestionnaire(urlVersion); + } + + protected void addItem(QuestionnaireResponse questionnaireResponse, String linkId, String text, Type answer) + { + List answerComponent = Collections + .singletonList(new QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().setValue(answer)); + + questionnaireResponse.addItem().setLinkId(linkId).setText(text).setAnswer(answerComponent); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationIntegrationTest.java index a90058b7f..a97ae1850 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationIntegrationTest.java @@ -18,9 +18,6 @@ import org.hl7.fhir.r4.model.StringType; import org.junit.Test; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.Response.Status; - public class OrganizationIntegrationTest extends AbstractIntegrationTest { @Test @@ -138,7 +135,7 @@ public void testUpdateOrganizationWithNewThumbprint() throws Exception getWebserviceClient().update(org); } - @Test(expected = WebApplicationException.class) + @Test public void testUpdateOrganizationWithExistingThumbprint() throws Exception { Bundle bundle1 = getWebserviceClient().search(Organization.class, Map.of("identifier", @@ -181,18 +178,10 @@ public void testUpdateOrganizationWithExistingThumbprint() throws Exception thumbprints2.get(0).setValue(new StringType(existingThumbprint)); - try - { - getWebserviceClient().update(org2); - } - catch (WebApplicationException e) - { - assertEquals(Status.FORBIDDEN.getStatusCode(), e.getResponse().getStatus()); - throw e; - } + expectForbidden(() -> getWebserviceClient().update(org2)); } - @Test(expected = WebApplicationException.class) + @Test public void testUpdateOrganizationWithExistingIdentifier() throws Exception { Bundle bundle = getWebserviceClient().search(Organization.class, Map.of("identifier", @@ -210,15 +199,7 @@ public void testUpdateOrganizationWithExistingIdentifier() throws Exception Organization org = (Organization) bundle.getEntryFirstRep().getResource(); org.getIdentifierFirstRep().setValue("Test_Organization"); - try - { - getWebserviceClient().update(org); - } - catch (WebApplicationException e) - { - assertEquals(Status.FORBIDDEN.getStatusCode(), e.getResponse().getStatus()); - throw e; - } + expectForbidden(() -> getWebserviceClient().update(org)); } @Test @@ -270,18 +251,10 @@ public void testSearchWithUnsupportedRevIncludeParameter() throws Exception assertTrue(outcomeEntry.getResource() instanceof OperationOutcome); } - @Test(expected = WebApplicationException.class) + @Test public void testStrictSearchWithUnsupportedRevIncludeParameter() throws Exception { - try - { - getWebserviceClient().searchWithStrictHandling(Organization.class, - Map.of("_revinclude", Collections.singletonList("Endpoint:foo"))); - } - catch (WebApplicationException e) - { - assertEquals(Status.BAD_REQUEST.getStatusCode(), e.getResponse().getStatus()); - throw e; - } + expectBadRequest(() -> getWebserviceClient().searchWithStrictHandling(Organization.class, + Map.of("_revinclude", Collections.singletonList("Endpoint:foo")))); } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireIntegrationTest.java index bf6f02b7b..8a38df47f 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireIntegrationTest.java @@ -4,53 +4,21 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import java.time.LocalDateTime; -import java.time.ZoneOffset; import java.util.Collections; -import java.util.Date; import java.util.Map; -import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Enumerations; import org.hl7.fhir.r4.model.Questionnaire; import org.junit.Test; import dev.dsf.fhir.dao.QuestionnaireDao; -public class QuestionnaireIntegrationTest extends AbstractIntegrationTest +public class QuestionnaireIntegrationTest extends AbstractQuestionnaireIntegrationTest { - private static final Date DATE = Date.from(LocalDateTime.parse("2022-01-01T00:00:00").toInstant(ZoneOffset.UTC)); - private static final String IDENTIFIER_SYSTEM = "http://dsf.dev/fhir/CodeSystem/user-task"; - private static final String IDENTIFIER_VALUE = "foo"; - private static final String URL = "http://dsf.dev/fhir/Questionnaire/userTask/foo"; - private static final String VERSION = "1.0.0"; - private static final Enumerations.PublicationStatus STATUS = Enumerations.PublicationStatus.ACTIVE; - - private Questionnaire createQuestionnaire() - { - Questionnaire questionnaire = new Questionnaire(); - questionnaire.getMeta().addTag().setSystem("http://dsf.dev/fhir/CodeSystem/read-access-tag").setCode("ALL"); - - questionnaire.addIdentifier().setSystem(IDENTIFIER_SYSTEM).setValue(IDENTIFIER_VALUE); - - questionnaire.setUrl(URL); - questionnaire.setVersion(VERSION); - - questionnaire.setStatus(STATUS); - questionnaire.setDate(DATE); - - questionnaire.addItem().setLinkId("foo").setText("Approve?") - .setType(Questionnaire.QuestionnaireItemType.BOOLEAN).addInitial().setValue(new BooleanType(false)); - - return questionnaire; - } - @Test - public void testCreateValidByLocalUser() throws Exception + public void testCreateValidByLocalUser() { - Questionnaire questionnaire = createQuestionnaire(); - + Questionnaire questionnaire = createQuestionnaireProfileVersion100(); Questionnaire created = getWebserviceClient().create(questionnaire); assertNotNull(created); @@ -61,7 +29,7 @@ public void testCreateValidByLocalUser() throws Exception @Test public void testSearchByDate() throws Exception { - Questionnaire questionnaire = createQuestionnaire(); + Questionnaire questionnaire = createQuestionnaireProfileVersion100(); QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); questionnaireDao.create(questionnaire); @@ -76,18 +44,18 @@ public void testSearchByDate() throws Exception Questionnaire searchQuestionnaire = (Questionnaire) searchBundle.getEntry().get(0).getResource(); assertTrue(searchQuestionnaire.hasDate()); - assertEquals(0, DATE.compareTo(searchQuestionnaire.getDate())); + assertEquals(0, QUESTIONNAIRE_DATE.compareTo(searchQuestionnaire.getDate())); } @Test public void testSearchByIdentifier() throws Exception { - Questionnaire questionnaire = createQuestionnaire(); + Questionnaire questionnaire = createQuestionnaireProfileVersion100(); QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); questionnaireDao.create(questionnaire); Bundle searchBundle = getWebserviceClient().search(Questionnaire.class, - Map.of("identifier", Collections.singletonList(IDENTIFIER_SYSTEM + "|" + IDENTIFIER_VALUE))); + Map.of("identifier", Collections.singletonList(TEST_IDENTIFIER_SYSTEM + "|" + TEST_IDENTIFIER_VALUE))); assertNotNull(searchBundle.getEntry()); assertEquals(1, searchBundle.getEntry().size()); @@ -97,19 +65,19 @@ public void testSearchByIdentifier() throws Exception Questionnaire searchQuestionnaire = (Questionnaire) searchBundle.getEntry().get(0).getResource(); assertEquals(1, searchQuestionnaire.getIdentifier().size()); - assertEquals(IDENTIFIER_SYSTEM, searchQuestionnaire.getIdentifier().get(0).getSystem()); - assertEquals(IDENTIFIER_VALUE, searchQuestionnaire.getIdentifier().get(0).getValue()); + assertEquals(TEST_IDENTIFIER_SYSTEM, searchQuestionnaire.getIdentifier().get(0).getSystem()); + assertEquals(TEST_IDENTIFIER_VALUE, searchQuestionnaire.getIdentifier().get(0).getValue()); } @Test public void testSearchByStatus() throws Exception { - Questionnaire questionnaire = createQuestionnaire(); + Questionnaire questionnaire = createQuestionnaireProfileVersion100(); QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); questionnaireDao.create(questionnaire); Bundle searchBundle = getWebserviceClient().search(Questionnaire.class, - Map.of("status", Collections.singletonList(STATUS.toCode()))); + Map.of("status", Collections.singletonList(QUESTIONNAIRE_STATUS.toCode()))); assertNotNull(searchBundle.getEntry()); assertEquals(1, searchBundle.getEntry().size()); @@ -119,18 +87,19 @@ public void testSearchByStatus() throws Exception Questionnaire searchQuestionnaire = (Questionnaire) searchBundle.getEntry().get(0).getResource(); assertTrue(searchQuestionnaire.hasStatus()); - assertEquals(STATUS, searchQuestionnaire.getStatus()); + assertEquals(QUESTIONNAIRE_STATUS, searchQuestionnaire.getStatus()); } @Test public void testSearchByUrlAndVersion() throws Exception { - Questionnaire questionnaire = createQuestionnaire(); + Questionnaire questionnaire = createQuestionnaireProfileVersion100(); QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); questionnaireDao.create(questionnaire); Bundle searchBundle = getWebserviceClient().search(Questionnaire.class, - Map.of("url", Collections.singletonList(URL), "version", Collections.singletonList(VERSION))); + Map.of("url", Collections.singletonList(QUESTIONNAIRE_URL), "version", + Collections.singletonList(QUESTIONNAIRE_VERSION))); assertNotNull(searchBundle.getEntry()); assertEquals(1, searchBundle.getEntry().size()); @@ -140,8 +109,8 @@ public void testSearchByUrlAndVersion() throws Exception Questionnaire searchQuestionnaire = (Questionnaire) searchBundle.getEntry().get(0).getResource(); assertTrue(searchQuestionnaire.hasUrl()); - assertEquals(URL, searchQuestionnaire.getUrl()); + assertEquals(QUESTIONNAIRE_URL, searchQuestionnaire.getUrl()); assertTrue(searchQuestionnaire.hasVersion()); - assertEquals(VERSION, searchQuestionnaire.getVersion()); + assertEquals(QUESTIONNAIRE_VERSION, searchQuestionnaire.getVersion()); } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseAgainstQuestionnaireIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseAgainstQuestionnaireIntegrationTest.java new file mode 100644 index 000000000..66fa2ff14 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseAgainstQuestionnaireIntegrationTest.java @@ -0,0 +1,149 @@ +package dev.dsf.fhir.integration; + +import static org.junit.Assert.assertNotNull; + +import java.util.Optional; + +import org.hl7.fhir.r4.model.Questionnaire; +import org.hl7.fhir.r4.model.QuestionnaireResponse; +import org.hl7.fhir.r4.model.StringType; +import org.junit.Test; + +import dev.dsf.fhir.dao.QuestionnaireDao; + +public class QuestionnaireResponseAgainstQuestionnaireIntegrationTest extends AbstractQuestionnaireIntegrationTest +{ + @Test + public void testQuestionnaireResponseQuestionnaireCanonicalChanged() throws Exception + { + Questionnaire questionnaire = createQuestionnaireProfileVersion150("1.0.0"); + Questionnaire questionnaire2 = createQuestionnaireProfileVersion150("2.0.0"); + QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); + questionnaireDao.create(questionnaire); + questionnaireDao.create(questionnaire2); + + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.0.0"); + QuestionnaireResponse created = getWebserviceClient().create(questionnaireResponse); + + created.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED); + String newQuestionnaireUrlAndVersion = created.getQuestionnaire().replace("1.0.0", "2.0.0"); + created.setQuestionnaire(newQuestionnaireUrlAndVersion); + + expectForbidden(() -> getWebserviceClient().update(created)); + } + + @Test + public void testQuestionnaireResponseValidatesAgainstQuestionnaireProfilVersion100QuestionnaireNotFound() + throws Exception + { + Questionnaire questionnaire = createQuestionnaireProfileVersion150("1.0.1"); + QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); + questionnaireDao.create(questionnaire); + + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("2.0.1"); + expectForbidden(() -> getWebserviceClient().create(questionnaireResponse)); + } + + @Test + public void testQuestionnaireResponseValidatesAgainstQuestionnaireProfilVersion100ItemSet() throws Exception + { + Questionnaire questionnaire = createQuestionnaireProfileVersion150("1.0.2"); + addItem(questionnaire, "test", "test-item", Questionnaire.QuestionnaireItemType.STRING, Optional.empty()); + + QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); + questionnaireDao.create(questionnaire); + + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.0.2"); + QuestionnaireResponse createdQr = getWebserviceClient().create(questionnaireResponse); + + createdQr.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED); + addItem(createdQr, "test", "test-item", new StringType("answer")); + QuestionnaireResponse updatedQr = getWebserviceClient().update(createdQr); + + assertNotNull(updatedQr); + assertNotNull(updatedQr.getIdElement().getIdPart()); + assertNotNull(updatedQr.getIdElement().getVersionIdPart()); + } + + @Test + public void testQuestionnaireResponseValidatesAgainstQuestionnaireProfilVersion100ItemMissing() throws Exception + { + // expected to work without validation error, since not setting Questionnaire.item.required means the item is + // not required + Questionnaire questionnaire = createQuestionnaireProfileVersion150("1.0.3"); + addItem(questionnaire, "test", "test-item", Questionnaire.QuestionnaireItemType.STRING, Optional.empty()); + + QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); + questionnaireDao.create(questionnaire); + + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.0.3"); + QuestionnaireResponse createdQr = getWebserviceClient().create(questionnaireResponse); + + createdQr.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED); + QuestionnaireResponse updatedQr = getWebserviceClient().update(createdQr); + + assertNotNull(updatedQr); + assertNotNull(updatedQr.getIdElement().getIdPart()); + assertNotNull(updatedQr.getIdElement().getVersionIdPart()); + } + + @Test + public void testQuestionnaireResponseValidatesAgainstQuestionnaireProfileVersion150ItemRequiredAndSet() + throws Exception + { + Questionnaire questionnaire = createQuestionnaireProfileVersion150("1.5.1"); + addItem(questionnaire, "test", "test-item", Questionnaire.QuestionnaireItemType.STRING, Optional.of(true)); + + QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); + questionnaireDao.create(questionnaire); + + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.5.1"); + QuestionnaireResponse createdQr = getWebserviceClient().create(questionnaireResponse); + + createdQr.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED); + addItem(createdQr, "test", "test-item", new StringType("answer")); + QuestionnaireResponse updatedQr = getWebserviceClient().update(createdQr); + + assertNotNull(updatedQr); + assertNotNull(updatedQr.getIdElement().getIdPart()); + assertNotNull(updatedQr.getIdElement().getVersionIdPart()); + } + + @Test + public void testQuestionnaireResponseValidatesAgainstQuestionnaireProfileVersion150ItemRequiredNotSet() + throws Exception + { + Questionnaire questionnaire = createQuestionnaireProfileVersion150("1.5.2"); + addItem(questionnaire, "test", "test-item", Questionnaire.QuestionnaireItemType.STRING, Optional.of(true)); + + QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); + questionnaireDao.create(questionnaire); + + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.5.2"); + QuestionnaireResponse createdQr = getWebserviceClient().create(questionnaireResponse); + + createdQr.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED); + expectForbidden(() -> getWebserviceClient().update(createdQr)); + } + + @Test + public void testQuestionnaireResponseValidatesAgainstQuestionnaireProfileVersion150ItemOptionalNotSet() + throws Exception + { + Questionnaire questionnaire = createQuestionnaireProfileVersion150("1.5.3"); + addItem(questionnaire, "test", "test-item", Questionnaire.QuestionnaireItemType.STRING, Optional.of(false)); + + QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); + questionnaireDao.create(questionnaire); + + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.5.3"); + QuestionnaireResponse createdQr = getWebserviceClient().create(questionnaireResponse); + + createdQr.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED); + QuestionnaireResponse updatedQr = getWebserviceClient().update(createdQr); + + assertNotNull(updatedQr); + assertNotNull(updatedQr.getIdElement().getIdPart()); + assertNotNull(updatedQr.getIdElement().getVersionIdPart()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseIntegrationTest.java index 7bcf32e5d..c2ea85536 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseIntegrationTest.java @@ -6,25 +6,17 @@ import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; -import java.time.LocalDateTime; -import java.time.ZoneOffset; import java.util.Collections; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.stream.Collectors; -import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Enumerations; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Questionnaire; import org.hl7.fhir.r4.model.QuestionnaireResponse; import org.hl7.fhir.r4.model.QuestionnaireResponse.QuestionnaireResponseStatus; -import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.StringType; -import org.hl7.fhir.r4.model.Type; import org.junit.Test; import dev.dsf.fhir.authentication.OrganizationProvider; @@ -33,30 +25,25 @@ import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response.Status; -public class QuestionnaireResponseIntegrationTest extends AbstractIntegrationTest +public class QuestionnaireResponseIntegrationTest extends AbstractQuestionnaireIntegrationTest { - private static final String CODESYSTEM_DSF_BPMN_USER_TASK_VALUE_USER_TASK_ID = "user-task-id"; - - private static final Date AUTHORED = Date - .from(LocalDateTime.parse("2022-01-01T00:00:00").toInstant(ZoneOffset.UTC)); - private static final String QUESTIONNAIRE_URL = "http://dsf.dev/fhir/Questionnaire/userTask/foo"; - private static final String QUESTIONNAIRE_VERSION = "1.0.0"; - private static final String QUESTIONNAIRE = QUESTIONNAIRE_URL + "|" + QUESTIONNAIRE_VERSION; - private static final QuestionnaireResponse.QuestionnaireResponseStatus STATUS = QuestionnaireResponse.QuestionnaireResponseStatus.INPROGRESS; - @Test public void testCreateValidByLocalUser() throws Exception { - QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); + Questionnaire questionnaire = createQuestionnaireProfileVersion100(); + QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); + questionnaireDao.create(questionnaire); + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); QuestionnaireResponse created = getWebserviceClient().create(questionnaireResponse); + assertNotNull(created); assertNotNull(created.getIdElement().getIdPart()); assertNotNull(created.getIdElement().getVersionIdPart()); } @Test(expected = WebApplicationException.class) - public void testCreateNotAllowedByLocalUser() throws Exception + public void testCreateNotAllowedByLocalUser() { QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); questionnaireResponse.setStatus(QuestionnaireResponseStatus.COMPLETED); @@ -73,7 +60,7 @@ public void testCreateNotAllowedByLocalUser() throws Exception } @Test(expected = WebApplicationException.class) - public void testCreateNotAllowedByRemoteUser() throws Exception + public void testCreateNotAllowedByRemoteUser() { QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); @@ -91,6 +78,10 @@ public void testCreateNotAllowedByRemoteUser() throws Exception @Test public void testUpdateAllowedByLocalUser() throws Exception { + Questionnaire questionnaire = createQuestionnaireProfileVersion100(); + QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); + questionnaireDao.create(questionnaire); + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); QuestionnaireResponseDao questionnaireResponseDao = getSpringWebApplicationContext() .getBean(QuestionnaireResponseDao.class); @@ -126,7 +117,7 @@ public void testUpdateNotAllowedByLocalUser() throws Exception } @Test(expected = WebApplicationException.class) - public void testUpdateNotAllowedByLocalUserNowUserTaskId() throws Exception + public void testUpdateNotAllowedByLocalUserNoUserTaskId() throws Exception { QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); QuestionnaireResponseDao questionnaireResponseDao = getSpringWebApplicationContext() @@ -157,7 +148,8 @@ public void testUpdateNotAllowedByLocalUserChangedUserTaskId() throws Exception created.setStatus(QuestionnaireResponseStatus.STOPPED); created.getItem().clear(); - addItem(created, CODESYSTEM_DSF_BPMN_USER_TASK_VALUE_USER_TASK_ID, "UserTask ID", + + addItem(created, QUESTIONNAIRE_ITEM_USER_TASK_ID_LINK, QUESTIONNAIRE_ITEM_USER_TASK_ID_TEXT, new StringType(UUID.randomUUID().toString())); try @@ -232,23 +224,19 @@ public void testSearchByDate() throws Exception QuestionnaireResponse searchQuestionnaireResponse = (QuestionnaireResponse) searchBundle.getEntry().get(0) .getResource(); assertTrue(searchQuestionnaireResponse.hasAuthored()); - assertEquals(0, AUTHORED.compareTo(searchQuestionnaireResponse.getAuthored())); + assertEquals(0, QUESTIONNAIRE_RESPONSE_DATE.compareTo(searchQuestionnaireResponse.getAuthored())); } @Test public void testSearchByIdentifier() throws Exception { - final String value = UUID.randomUUID().toString(); - final String system = "http://foo/fhir/sid/Test"; - QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); - questionnaireResponse.getIdentifier().setSystem(system).setValue(value); QuestionnaireResponseDao questionnaireResponseDao = getSpringWebApplicationContext() .getBean(QuestionnaireResponseDao.class); questionnaireResponseDao.create(questionnaireResponse); Bundle searchBundle = getWebserviceClient().search(QuestionnaireResponse.class, - Map.of("identifier", Collections.singletonList(system + "|" + value))); + Map.of("identifier", Collections.singletonList(TEST_IDENTIFIER_SYSTEM + "|" + TEST_IDENTIFIER_VALUE))); assertNotNull(searchBundle.getEntry()); assertEquals(1, searchBundle.getEntry().size()); @@ -259,22 +247,20 @@ public void testSearchByIdentifier() throws Exception QuestionnaireResponse foundQuestionnaireResponse = (QuestionnaireResponse) searchBundle.getEntry().get(0) .getResource(); assertTrue(foundQuestionnaireResponse.hasIdentifier()); + assertEquals(TEST_IDENTIFIER_SYSTEM, foundQuestionnaireResponse.getIdentifier().getSystem()); + assertEquals(TEST_IDENTIFIER_VALUE, foundQuestionnaireResponse.getIdentifier().getValue()); } @Test public void testSearchByIdentifierRemoteUser() throws Exception { - final String value = UUID.randomUUID().toString(); - final String system = "http://foo/fhir/sid/Test"; - QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); - questionnaireResponse.getIdentifier().setSystem(system).setValue(value); QuestionnaireResponseDao questionnaireResponseDao = getSpringWebApplicationContext() .getBean(QuestionnaireResponseDao.class); questionnaireResponseDao.create(questionnaireResponse); Bundle searchBundle = getExternalWebserviceClient().search(QuestionnaireResponse.class, - Map.of("identifier", Collections.singletonList(system + "|" + value))); + Map.of("identifier", Collections.singletonList(TEST_IDENTIFIER_SYSTEM + "|" + TEST_IDENTIFIER_VALUE))); assertNotNull(searchBundle.getEntry()); assertEquals(0, searchBundle.getEntry().size()); @@ -283,7 +269,7 @@ public void testSearchByIdentifierRemoteUser() throws Exception @Test public void testSearchByQuestionnaireWithVersion() throws Exception { - testSearchByQuestionnaire(QUESTIONNAIRE); + testSearchByQuestionnaire(QUESTIONNAIRE_URL_VERSION); } @Test @@ -294,7 +280,7 @@ public void testSearchByQuestionnaireWithoutVersion() throws Exception private void testSearchByQuestionnaire(String questionnaireUrl) throws Exception { - Questionnaire questionnaire = createQuestionnaire(); + Questionnaire questionnaire = createQuestionnaireProfileVersion100(); QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); questionnaireDao.create(questionnaire); @@ -316,7 +302,7 @@ private void testSearchByQuestionnaire(String questionnaireUrl) throws Exception QuestionnaireResponse searchQuestionnaireResponse = (QuestionnaireResponse) searchBundle.getEntry().get(0) .getResource(); assertTrue(searchQuestionnaireResponse.hasQuestionnaire()); - assertEquals(QUESTIONNAIRE, searchQuestionnaireResponse.getQuestionnaire()); + assertEquals(QUESTIONNAIRE_URL_VERSION, searchQuestionnaireResponse.getQuestionnaire()); assertNotNull(searchBundle.getEntry().get(1)); assertNotNull(searchBundle.getEntry().get(1).getResource()); @@ -332,7 +318,7 @@ private void testSearchByQuestionnaire(String questionnaireUrl) throws Exception @Test public void testSearchByQuestionnaireNoVersion() throws Exception { - Questionnaire questionnaire = createQuestionnaire().setVersion(null); + Questionnaire questionnaire = createQuestionnaireProfileVersion100().setVersion(null); QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); questionnaireDao.create(questionnaire); @@ -371,16 +357,16 @@ public void testSearchByQuestionnaireWithoutVersionButMultipleVersionExist() thr { QuestionnaireDao questionnaireDao = getSpringWebApplicationContext().getBean(QuestionnaireDao.class); - Questionnaire questionnaire1 = createQuestionnaire().setVersion("0.1.0"); + Questionnaire questionnaire1 = createQuestionnaireProfileVersion100().setVersion("0.1.0"); questionnaireDao.create(questionnaire1); - Questionnaire questionnaire2 = createQuestionnaire(); + Questionnaire questionnaire2 = createQuestionnaireProfileVersion100(); questionnaireDao.create(questionnaire2); - Questionnaire questionnaire3 = createQuestionnaire().setVersion("0.2.0"); + Questionnaire questionnaire3 = createQuestionnaireProfileVersion100().setVersion("0.2.0"); questionnaireDao.create(questionnaire3); - Questionnaire questionnaire4 = createQuestionnaire().setVersion(null); + Questionnaire questionnaire4 = createQuestionnaireProfileVersion100().setVersion(null); questionnaireDao.create(questionnaire4); QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); @@ -401,7 +387,7 @@ public void testSearchByQuestionnaireWithoutVersionButMultipleVersionExist() thr QuestionnaireResponse searchQuestionnaireResponse = (QuestionnaireResponse) searchBundle.getEntry().get(0) .getResource(); assertTrue(searchQuestionnaireResponse.hasQuestionnaire()); - assertEquals(QUESTIONNAIRE, searchQuestionnaireResponse.getQuestionnaire()); + assertEquals(QUESTIONNAIRE_URL_VERSION, searchQuestionnaireResponse.getQuestionnaire()); assertNotNull(searchBundle.getEntry().get(1)); assertNotNull(searchBundle.getEntry().get(1).getResource()); @@ -425,7 +411,7 @@ public void testSearchByStatus() throws Exception questionnaireResponseDao.create(questionnaireResponse); Bundle searchBundle = getWebserviceClient().search(QuestionnaireResponse.class, - Map.of("status", Collections.singletonList(STATUS.toCode()))); + Map.of("status", Collections.singletonList(QUESTIONNAIRE_RESPONSE_STATUS.toCode()))); assertNotNull(searchBundle.getEntry()); assertEquals(1, searchBundle.getEntry().size()); @@ -436,7 +422,7 @@ public void testSearchByStatus() throws Exception QuestionnaireResponse searchQuestionnaireResponse = (QuestionnaireResponse) searchBundle.getEntry().get(0) .getResource(); assertTrue(searchQuestionnaireResponse.hasStatus()); - assertEquals(STATUS, searchQuestionnaireResponse.getStatus()); + assertEquals(QUESTIONNAIRE_RESPONSE_STATUS, searchQuestionnaireResponse.getStatus()); } @Test @@ -449,9 +435,9 @@ public void testSearchBySubjectReference() throws Exception OrganizationProvider organizationProvider = getSpringWebApplicationContext() .getBean(OrganizationProvider.class); - Organization organization = organizationProvider.getLocalOrganization().get(); + Organization localOrganization = organizationProvider.getLocalOrganization().get(); + String organizationReference = "Organization/" + localOrganization.getIdElement().getIdPart(); - String organizationReference = "Organization/" + organization.getIdElement().getIdPart(); Bundle searchBundle = getWebserviceClient().search(QuestionnaireResponse.class, Map.of("subject", Collections.singletonList(organizationReference), "_include", Collections.singletonList("QuestionnaireResponse:subject:Organization"))); @@ -472,59 +458,12 @@ public void testSearchBySubjectReference() throws Exception assertTrue(searchBundle.getEntry().get(1).getResource() instanceof Organization); Organization searchOrganization = (Organization) searchBundle.getEntry().get(1).getResource(); - assertEquals(organization.getIdentifierFirstRep().getSystem(), + assertEquals(localOrganization.getIdentifierFirstRep().getSystem(), searchOrganization.getIdentifierFirstRep().getSystem()); - assertEquals(organization.getIdentifierFirstRep().getValue(), + assertEquals(localOrganization.getIdentifierFirstRep().getValue(), searchOrganization.getIdentifierFirstRep().getValue()); } - private Questionnaire createQuestionnaire() - { - Questionnaire questionnaire = new Questionnaire(); - questionnaire.getMeta().addTag().setSystem("http://dsf.dev/fhir/CodeSystem/read-access-tag").setCode("ALL"); - - questionnaire.setUrl(QUESTIONNAIRE_URL); - questionnaire.setVersion(QUESTIONNAIRE_VERSION); - - questionnaire.setStatus(Enumerations.PublicationStatus.ACTIVE); - - questionnaire.addItem().setLinkId("foo").setText("Approve?") - .setType(Questionnaire.QuestionnaireItemType.BOOLEAN).addInitial().setValue(new BooleanType(false)); - - return questionnaire; - } - - private QuestionnaireResponse createQuestionnaireResponse() - { - OrganizationProvider organizationProvider = getSpringWebApplicationContext() - .getBean(OrganizationProvider.class); - assertNotNull(organizationProvider); - - QuestionnaireResponse questionnaireResponse = new QuestionnaireResponse(); - - questionnaireResponse.setQuestionnaire(QUESTIONNAIRE); - - questionnaireResponse.setStatus(STATUS); - questionnaireResponse.setAuthored(AUTHORED); - - String organizationReference = "Organization/" - + organizationProvider.getLocalOrganization().get().getIdElement().getIdPart(); - questionnaireResponse.setSubject(new Reference(organizationReference)); - - addItem(questionnaireResponse, CODESYSTEM_DSF_BPMN_USER_TASK_VALUE_USER_TASK_ID, "UserTask ID", - new StringType(UUID.randomUUID().toString())); - - return questionnaireResponse; - } - - private void addItem(QuestionnaireResponse questionnaireResponse, String linkId, String text, Type answer) - { - List answerComponent = Collections - .singletonList(new QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent().setValue(answer)); - - questionnaireResponse.addItem().setLinkId(linkId).setText(text).setAnswer(answerComponent); - } - @Test public void testDeleteAllowedByLocalUser() throws Exception { @@ -712,7 +651,7 @@ public void testHistory() throws Exception List qrFromBundle = historyBundle3.getEntry().stream() .filter(e -> e.hasResource() && e.getResource() instanceof QuestionnaireResponse) - .map(e -> (QuestionnaireResponse) e.getResource()).collect(Collectors.toList()); + .map(e -> (QuestionnaireResponse) e.getResource()).toList(); assertEquals(1, qrFromBundle.size()); assertNotNull(qrFromBundle.get(0)); @@ -743,7 +682,7 @@ public void testHistoryRemoteUser() throws Exception List qrFromBundle = historyBundle3.getEntry().stream() .filter(e -> e.hasResource() && e.getResource() instanceof QuestionnaireResponse) - .map(e -> (QuestionnaireResponse) e.getResource()).collect(Collectors.toList()); + .map(e -> (QuestionnaireResponse) e.getResource()).toList(); assertEquals(0, qrFromBundle.size()); } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java index a3abc6239..b997f271e 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/TaskIntegrationTest.java @@ -57,7 +57,7 @@ public class TaskIntegrationTest extends AbstractIntegrationTest { private static final Logger logger = LoggerFactory.getLogger(TaskIntegrationTest.class); - @Test(expected = WebApplicationException.class) + @Test public void testCreateTaskStartPingProcessNotAllowedForRemoteUser() throws Exception { OrganizationProvider organizationProvider = getSpringWebApplicationContext() @@ -81,15 +81,7 @@ public void testCreateTaskStartPingProcessNotAllowedForRemoteUser() throws Excep .setCode("message-name"); t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); - try - { - getExternalWebserviceClient().create(t); - } - catch (WebApplicationException e) - { - assertEquals(Status.FORBIDDEN.getStatusCode(), e.getResponse().getStatus()); - throw e; - } + expectForbidden(() -> getExternalWebserviceClient().create(t)); } @Test @@ -116,12 +108,13 @@ public void testCreateForbiddenLocalUserIllegalStatus() throws Exception t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.setStatus(null); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); for (TaskStatus illegal : illegalCreateStates) { t.setStatus(illegal); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); + ; } } @@ -151,38 +144,12 @@ public void testCreateForbiddenExternalUserIllegalStatus() throws Exception t.getInputFirstRep().setValue(new StringType("pingMessage")); t.setStatus(null); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); for (TaskStatus illegal : illegalCreateStates) { t.setStatus(illegal); - testCreateExpectForbidden(getExternalWebserviceClient(), t); - } - } - - private void testCreateExpectForbidden(FhirWebserviceClient client, Task task) throws Exception - { - try - { - client.create(task); - fail("WebApplicationException expected"); - } - catch (WebApplicationException e) - { - assertEquals(403, e.getResponse().getStatus()); - } - } - - private void testUpdateExpectForbidden(FhirWebserviceClient client, Task task) throws Exception - { - try - { - client.update(task); - fail("WebApplicationException expected"); - } - catch (WebApplicationException e) - { - assertEquals(403, e.getResponse().getStatus()); + expectForbidden(() -> getExternalWebserviceClient().create(t)); } } @@ -206,21 +173,21 @@ public void testCreateForbiddenLocalUserNotPartOfRequesterOrganization() throws t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.setRequester(null); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.setRequester(new Reference()); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); Reference requester1 = new Reference().setType("Organization"); requester1.getIdentifier().setSystem("http://dsf.dev/sid/organization-identifier") .setValue("External_Test_Organization"); t.setRequester(requester1); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); Reference requester2 = new Reference() .setReference("http://foo.test/fhir/Organization/" + UUID.randomUUID().toString()); t.setRequester(requester2); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); } @Test @@ -242,20 +209,20 @@ public void testCreateForbiddenExternalUserNotPartOfRequesterOrganization() thro t.getInputFirstRep().setValue(new StringType("pingMessage")); t.setRequester(null); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.setRequester(new Reference()); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); Reference requester1 = new Reference() .setReferenceElement(organizationProvider.getLocalOrganization().get().getIdElement().toVersionless()); t.setRequester(requester1); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); Reference requester2 = new Reference() .setReference("http://foo.test/fhir/Organization/" + UUID.randomUUID().toString()); t.setRequester(requester2); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); } @Test @@ -278,37 +245,37 @@ public void testCreateForbiddenLocalUserRestrictionRecipientNotValidByLocalUser( t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.setRestriction(null); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.getRestriction().addExtension().setUrl("test"); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); Reference requester0 = new Reference().setReference("Organization/" + UUID.randomUUID().toString()); t.setRestriction(new TaskRestrictionComponent()); t.getRestriction().addRecipient(requester0); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); Reference requester1 = new Reference().setType("Organization"); requester1.getIdentifier().setSystem("http://dsf.dev/sid/organization-identifier") .setValue("External_Test_Organization"); t.setRestriction(new TaskRestrictionComponent()); t.getRestriction().addRecipient(requester1); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); Reference requester2 = new Reference() .setReference("http://foo.test/fhir/Organization/" + UUID.randomUUID().toString()); t.setRestriction(new TaskRestrictionComponent()); t.getRestriction().addRecipient(requester2); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.setRestriction(new TaskRestrictionComponent()); t.getRestriction().addRecipient(requester1).addRecipient(requester2); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.setRestriction(new TaskRestrictionComponent()); t.getRestriction().addRecipient(new Reference(organizationProvider.getLocalOrganization().get())) .addRecipient(requester0); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); } @Test @@ -333,37 +300,37 @@ public void testCreateForbiddenLocalUserRestrictionRecipientNotValidByExternalUs t.getInputFirstRep().setValue(new StringType("pingMessage")); t.setRestriction(null); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.getRestriction().addExtension().setUrl("test"); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); Reference requester0 = new Reference().setReference("Organization/" + UUID.randomUUID().toString()); t.setRestriction(new TaskRestrictionComponent()); t.getRestriction().addRecipient(requester0); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); Reference requester1 = new Reference().setType("Organization"); requester1.getIdentifier().setSystem("http://dsf.dev/sid/organization-identifier") .setValue("External_Test_Organization"); t.setRestriction(new TaskRestrictionComponent()); t.getRestriction().addRecipient(requester1); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); Reference requester2 = new Reference() .setReference("http://foo.test/fhir/Organization/" + UUID.randomUUID().toString()); t.setRestriction(new TaskRestrictionComponent()); t.getRestriction().addRecipient(requester2); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.setRestriction(new TaskRestrictionComponent()); t.getRestriction().addRecipient(requester1).addRecipient(requester2); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.setRestriction(new TaskRestrictionComponent()); t.getRestriction().addRecipient(new Reference(organizationProvider.getLocalOrganization().get())) .addRecipient(requester0); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); } @Test @@ -387,10 +354,10 @@ public void testCreateForbiddenInstantiatesUriNotValidByLocalUser() throws Excep t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.setInstantiatesCanonical(null); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.setInstantiatesCanonical("not-a-valid-pattern"); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); } @Test @@ -417,10 +384,10 @@ public void testCreateForbiddenInstantiatesUriNotValidByExternalUser() throws Ex t.getInputFirstRep().setValue(new StringType("pingMessage")); t.setInstantiatesCanonical(null); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.setInstantiatesCanonical("not-a-valid-pattern"); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); } @Test @@ -444,12 +411,12 @@ public void testCreateForbiddenInputNotValidByLocalUser() throws Exception // t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.setInput(null); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("system").setCode("code"); t.getInputFirstRep().setValue(new StringType("value")); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.setInput(null); ParameterComponent in1 = t.addInput(); @@ -460,30 +427,30 @@ public void testCreateForbiddenInputNotValidByLocalUser() throws Exception in2.getType().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/bpmn-message") .setCode("message-name"); in2.setValue(new StringType("startPingProcessMessage")); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/bpmn-message") .setCode(""); t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/bpmn-message") .setCode("message-name"); t.getInputFirstRep().setValue(new StringType("")); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/bpmn-message") .setCode("message-name"); t.getInputFirstRep().setValue(new Coding().setSystem("system").setCode("code")); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); } @Test @@ -510,12 +477,12 @@ public void testCreateForbiddenInputNotValidByExternalUser() throws Exception // t.getInputFirstRep().setValue(new StringType("pingMessage")); t.setInput(null); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("system").setCode("code"); t.getInputFirstRep().setValue(new StringType("value")); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.setInput(null); ParameterComponent in1 = t.addInput(); @@ -526,30 +493,30 @@ public void testCreateForbiddenInputNotValidByExternalUser() throws Exception in2.getType().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/bpmn-message") .setCode("message-name"); in2.setValue(new StringType("startPingProcessMessage")); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/bpmn-message") .setCode(""); t.getInputFirstRep().setValue(new StringType("pingMessage")); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/bpmn-message") .setCode("message-name"); t.getInputFirstRep().setValue(new StringType("")); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/bpmn-message") .setCode("message-name"); t.getInputFirstRep().setValue(new Coding().setSystem("system").setCode("code")); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); } @Test @@ -574,7 +541,7 @@ public void testCreateForbiddenOutputNotValidByLocalUser() throws Exception t.getOutputFirstRep().getType().getCodingFirstRep().setSystem("system").setCode("code"); t.getOutputFirstRep().setValue(new StringType("value")); - testCreateExpectForbidden(getWebserviceClient(), t); + expectForbidden(() -> getWebserviceClient().create(t)); } @Test @@ -602,7 +569,7 @@ public void testCreateForbiddenOutputNotValidByExternalUser() throws Exception t.getOutputFirstRep().getType().getCodingFirstRep().setSystem("system").setCode("code"); t.getOutputFirstRep().setValue(new StringType("value")); - testCreateExpectForbidden(getExternalWebserviceClient(), t); + expectForbidden(() -> getExternalWebserviceClient().create(t)); } @Test @@ -724,7 +691,7 @@ public void testCreateTaskNotAllowedLocalUserWithoutRole() throws Exception assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getPractitionerWebserviceClient(), task); + expectForbidden(() -> getPractitionerWebserviceClient().create(task)); } @Test @@ -760,7 +727,7 @@ public void testCreateTaskNotAllowedLocalUserWithoutRole2() throws Exception assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getPractitionerWebserviceClient(), task); + expectForbidden(() -> getPractitionerWebserviceClient().create(task)); } @Test @@ -777,7 +744,7 @@ public void testCreateTaskNotAllowedLocalOrganizationWithoutRole2() throws Excep assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getWebserviceClient(), task); + expectForbidden(() -> getWebserviceClient().create(task)); } @Test @@ -813,7 +780,7 @@ public void testCreateTaskNotAllowedLocalUserWithoutRole3() throws Exception assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getPractitionerWebserviceClient(), task); + expectForbidden(() -> getPractitionerWebserviceClient().create(task)); } @Test @@ -830,7 +797,7 @@ public void testCreateTaskNotAllowedLocalOrganizationWithoutRole3() throws Excep assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getWebserviceClient(), task); + expectForbidden(() -> getWebserviceClient().create(task)); } @Test @@ -888,7 +855,7 @@ public void testCreateTaskNotAllowedRemoteUser() throws Exception assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("External_Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getExternalWebserviceClient(), task); + expectForbidden(() -> getExternalWebserviceClient().create(task)); } @Test @@ -905,7 +872,7 @@ public void testCreateTaskNotAllowedPractitioner1() throws Exception assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getPractitionerWebserviceClient(), task); + expectForbidden(() -> getPractitionerWebserviceClient().create(task)); } @Test @@ -941,7 +908,7 @@ public void testCreateTaskNotAllowedPractitioner11() throws Exception assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getPractitionerWebserviceClient(), task); + expectForbidden(() -> getPractitionerWebserviceClient().create(task)); } @Test @@ -977,7 +944,7 @@ public void testCreateTaskNotAllowedPractitioner12() throws Exception assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getPractitionerWebserviceClient(), task); + expectForbidden(() -> getPractitionerWebserviceClient().create(task)); } @Test @@ -1032,7 +999,7 @@ public void testCreateTaskNotAllowedLocalUser() throws Exception assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getWebserviceClient(), task); + expectForbidden(() -> getWebserviceClient().create(task)); } @Test @@ -1068,7 +1035,7 @@ public void testCreateTaskNotAllowedLocalUser2() throws Exception assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getWebserviceClient(), task); + expectForbidden(() -> getWebserviceClient().create(task)); } @Test @@ -1112,7 +1079,7 @@ public void testCreateTaskNotAllowedRemoteUser2() throws Exception assertNotNull(createdTestTaskProfile.getIdElement().getIdPart()); Task task = readTestTask("External_Test_Organization", "Test_Organization"); - testCreateExpectForbidden(getExternalWebserviceClient(), task); + expectForbidden(() -> getExternalWebserviceClient().create(task)); } @Test @@ -1483,7 +1450,7 @@ public void testCreateAllowViaDraftNotAllowedAsRequestedLocal() throws Exception task.getIdentifier().clear(); task.setStatus(TaskStatus.REQUESTED); - testCreateExpectForbidden(getWebserviceClient(), task); + expectForbidden(() -> getWebserviceClient().create(task)); } @Test @@ -1491,8 +1458,7 @@ public void testCreateForbiddenDraftTaskExternalOrganization() throws Exception { Task task = readTestTask("External_Test_Organization", "Test_Organization"); task.setStatus(TaskStatus.DRAFT); - - testCreateExpectForbidden(getExternalWebserviceClient(), task); + expectForbidden(() -> getExternalWebserviceClient().create(task)); } @Test @@ -1501,7 +1467,7 @@ public void testCreateForbiddenDraftTaskPractitionerIdentity() throws Exception Task task = readTestTask("Test_Organization", "Test_Organization"); task.setStatus(TaskStatus.DRAFT); - testCreateExpectForbidden(getPractitionerWebserviceClient(), task); + expectForbidden(() -> getPractitionerWebserviceClient().create(task)); } @Test @@ -1513,6 +1479,6 @@ public void testUpdateRequestedToInProgressForbiddenForExternal() throws Excepti Task createdTask = dao.create(task); createdTask.setStatus(TaskStatus.INPROGRESS); - testUpdateExpectForbidden(getExternalWebserviceClient(), createdTask); + expectForbidden(() -> getExternalWebserviceClient().update(createdTask)); } } diff --git a/dsf-fhir/dsf-fhir-validation/src/main/resources/fhir/StructureDefinition/dsf-questionnaire-1.5.0.xml b/dsf-fhir/dsf-fhir-validation/src/main/resources/fhir/StructureDefinition/dsf-questionnaire-1.5.0.xml new file mode 100644 index 000000000..a94b0a471 --- /dev/null +++ b/dsf-fhir/dsf-fhir-validation/src/main/resources/fhir/StructureDefinition/dsf-questionnaire-1.5.0.xml @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-validation/src/main/resources/fhir/StructureDefinition/dsf-questionnaire-1.5.0.xml.post b/dsf-fhir/dsf-fhir-validation/src/main/resources/fhir/StructureDefinition/dsf-questionnaire-1.5.0.xml.post new file mode 100644 index 000000000..776efe336 --- /dev/null +++ b/dsf-fhir/dsf-fhir-validation/src/main/resources/fhir/StructureDefinition/dsf-questionnaire-1.5.0.xml.post @@ -0,0 +1 @@ +url=http://dsf.dev/fhir/StructureDefinition/questionnaire&version=1.5.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-validation/src/test/java/dev/dsf/fhir/profiles/QuestionnaireProfileTest.java b/dsf-fhir/dsf-fhir-validation/src/test/java/dev/dsf/fhir/profiles/QuestionnaireProfileTest.java index 196452dc2..a41cf78c1 100644 --- a/dsf-fhir/dsf-fhir-validation/src/test/java/dev/dsf/fhir/profiles/QuestionnaireProfileTest.java +++ b/dsf-fhir/dsf-fhir-validation/src/test/java/dev/dsf/fhir/profiles/QuestionnaireProfileTest.java @@ -23,9 +23,13 @@ public class QuestionnaireProfileTest { private static final Logger logger = LoggerFactory.getLogger(QuestionnaireProfileTest.class); + private static final String VERSION_1_0_0 = "1.0.0"; + private static final String VERSION_1_5_0 = "1.5.0"; + @ClassRule public static final ValidationSupportRule validationRule = new ValidationSupportRule( - Arrays.asList("dsf-questionnaire-1.0.0.xml"), Collections.emptyList(), Collections.emptyList()); + Arrays.asList("dsf-questionnaire-1.0.0.xml", "dsf-questionnaire-1.5.0.xml"), Collections.emptyList(), + Collections.emptyList()); private final ResourceValidator resourceValidator = new ResourceValidatorImpl(validationRule.getFhirContext(), validationRule.getValidationSupport()); @@ -33,72 +37,83 @@ public class QuestionnaireProfileTest @Test public void testQuestionnaireValidTypeString() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.STRING); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.STRING); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.STRING); } @Test public void testQuestionnaireValidTypeText() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.TEXT); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.TEXT); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.TEXT); } @Test public void testQuestionnaireValidTypeInteger() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.INTEGER); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.INTEGER); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.INTEGER); } @Test public void testQuestionnaireValidTypeDecimal() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.DECIMAL); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.DECIMAL); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.DECIMAL); } @Test public void testQuestionnaireValidTypeBoolean() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.BOOLEAN); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.BOOLEAN); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.BOOLEAN); } @Test public void testQuestionnaireValidTypeDate() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.DATE); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.DATE); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.DATE); } @Test public void testQuestionnaireValidTypeTime() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.TIME); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.TIME); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.TIME); } @Test public void testQuestionnaireValidTypeDateTime() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.DATETIME); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.DATETIME); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.DATETIME); } @Test public void testQuestionnaireValidTypeUrl() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.URL); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.URL); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.URL); } @Test public void testQuestionnaireValidTypeReference() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.REFERENCE); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.REFERENCE); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.REFERENCE); } @Test public void testQuestionnaireValidTypeDisplay() { - testQuestionnaireValidType(Questionnaire.QuestionnaireItemType.DISPLAY); + testQuestionnaireValidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.DISPLAY); + testQuestionnaireValidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.DISPLAY); } - private void testQuestionnaireValidType(Questionnaire.QuestionnaireItemType type) + private void testQuestionnaireValidType(String profileVersion, Questionnaire.QuestionnaireItemType type) { - Questionnaire res = createQuestionnaire(type); + Questionnaire res = createQuestionnaire(profileVersion, type); ValidationResult result = resourceValidator.validate(res); result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" @@ -111,42 +126,48 @@ private void testQuestionnaireValidType(Questionnaire.QuestionnaireItemType type @Test public void testQuestionnaireInvalidTypeGroup() { - testQuestionnaireInvalidType(Questionnaire.QuestionnaireItemType.GROUP); + testQuestionnaireInvalidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.GROUP); + testQuestionnaireInvalidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.GROUP); } @Test public void testQuestionnaireInvalidTypeQuestion() { - testQuestionnaireInvalidType(Questionnaire.QuestionnaireItemType.QUESTION); + testQuestionnaireInvalidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.QUESTION); + testQuestionnaireInvalidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.QUESTION); } @Test public void testQuestionnaireInvalidTypeChoice() { - testQuestionnaireInvalidType(Questionnaire.QuestionnaireItemType.CHOICE); + testQuestionnaireInvalidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.CHOICE); + testQuestionnaireInvalidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.CHOICE); } @Test public void testQuestionnaireInvalidTypeOpenChoice() { - testQuestionnaireInvalidType(Questionnaire.QuestionnaireItemType.OPENCHOICE); + testQuestionnaireInvalidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.OPENCHOICE); + testQuestionnaireInvalidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.OPENCHOICE); } @Test public void testQuestionnaireInvalidTypeAttachment() { - testQuestionnaireInvalidType(Questionnaire.QuestionnaireItemType.ATTACHMENT); + testQuestionnaireInvalidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.ATTACHMENT); + testQuestionnaireInvalidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.ATTACHMENT); } @Test public void testQuestionnaireInvalidTypeQuantity() { - testQuestionnaireInvalidType(Questionnaire.QuestionnaireItemType.QUANTITY); + testQuestionnaireInvalidType(VERSION_1_0_0, Questionnaire.QuestionnaireItemType.QUANTITY); + testQuestionnaireInvalidType(VERSION_1_5_0, Questionnaire.QuestionnaireItemType.QUANTITY); } - private void testQuestionnaireInvalidType(Questionnaire.QuestionnaireItemType type) + private void testQuestionnaireInvalidType(String profileVersion, Questionnaire.QuestionnaireItemType type) { - Questionnaire res = createQuestionnaire(Questionnaire.QuestionnaireItemType.STRING); + Questionnaire res = createQuestionnaire(profileVersion, Questionnaire.QuestionnaireItemType.STRING); res.addItem().setLinkId("invalid-type").setType(type).setText("Invalid type"); ValidationResult result = resourceValidator.validate(res); @@ -161,19 +182,22 @@ private void testQuestionnaireInvalidType(Questionnaire.QuestionnaireItemType ty .count()); } - private Questionnaire createQuestionnaire(Questionnaire.QuestionnaireItemType type) + private Questionnaire createQuestionnaire(String profileVersion, Questionnaire.QuestionnaireItemType type) { Questionnaire res = new Questionnaire(); - res.getMeta().addProfile("http://dsf.dev/fhir/StructureDefinition/questionnaire"); + res.getMeta().addProfile("http://dsf.dev/fhir/StructureDefinition/questionnaire|" + profileVersion); res.setUrl("http://dsf.dev/fhir/Questionnaire/hello-world"); res.setVersion("0.1.0"); res.setDate(new Date()); res.setStatus(Enumerations.PublicationStatus.ACTIVE); res.addItem().setLinkId("business-key").setType(Questionnaire.QuestionnaireItemType.STRING) - .setText("The business-key of the process execution"); + .setText("The business-key of the process execution").setRequired(true); res.addItem().setLinkId("user-task-id").setType(Questionnaire.QuestionnaireItemType.STRING) - .setText("The user-task-id of the process execution"); - res.addItem().setLinkId("valid-type").setType(type).setText("valid type"); + .setText("The user-task-id of the process execution").setRequired(true); + + var item = res.addItem().setLinkId("valid-type").setType(type).setText("valid type"); + if (!Questionnaire.QuestionnaireItemType.DISPLAY.equals(type)) + item.setRequired(true); return res; }