diff options
Diffstat (limited to 'connector')
-rw-r--r-- | connector/src/main/java/at/asitplus/eidas/specific/connector/controller/AdresssucheController.java | 82 | ||||
-rw-r--r-- | connector/src/main/resources/templates/residency.html | 122 | ||||
-rw-r--r-- | connector/src/main/webapp/img/ajax-loader.gif | bin | 0 -> 673 bytes | |||
-rw-r--r-- | connector/src/test/resources/config/properties/messages.properties | 7 | ||||
-rw-r--r-- | connector/src/test/resources/config/properties/messages_de.properties | 9 | ||||
-rw-r--r-- | connector/src/test/resources/config/templates/residency.html | 122 | ||||
-rw-r--r-- | connector/src/test/resources/config/webcontent/img/ajax-loader.gif | bin | 0 -> 673 bytes |
7 files changed, 265 insertions, 77 deletions
diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/controller/AdresssucheController.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/controller/AdresssucheController.java index 8b25a7bd..c35aa8b9 100644 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/controller/AdresssucheController.java +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/controller/AdresssucheController.java @@ -35,8 +35,11 @@ import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; import at.gv.egiz.eaaf.core.exceptions.GuiBuildException; +import lombok.AllArgsConstructor; +import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.CompareToBuilder; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ResourceLoader; @@ -48,6 +51,8 @@ import org.springframework.web.bind.annotation.RequestParam; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.util.*; +import java.util.stream.Collectors; /** * Default process-engine signaling controller. @@ -88,7 +93,7 @@ public class AdresssucheController { } @RequestMapping(value = {"/residency/search"}, method = {RequestMethod.POST}) - public ResponseEntity<AdresssucheOutput> search(@RequestParam("municipality") String municipality, + public ResponseEntity<AdresssucheResult> search(@RequestParam("municipality") String municipality, @RequestParam("village") String village, @RequestParam("street") String street, @RequestParam("number") String number, @@ -104,7 +109,7 @@ public class AdresssucheController { try { Adressdaten searchInput = buildSearchInput(municipality, village, street, number); ZmrAddressSoapClient.AddressInfo searchOutput = client.searchAddress(searchInput); - AdresssucheOutput output = buildResponse(searchOutput); + AdresssucheResult output = buildResponse(searchOutput); return ResponseEntity.ok(output); } catch (EidasSAuthenticationException e) { log.warn("Search failed", e); @@ -112,18 +117,22 @@ public class AdresssucheController { } } - private AdresssucheOutput buildResponse(ZmrAddressSoapClient.AddressInfo searchOutput) { + private AdresssucheResult buildResponse(ZmrAddressSoapClient.AddressInfo searchOutput) { if (searchOutput.getPersonResult().isEmpty()) { log.warn("No result from ZMR"); - return new AdresssucheOutput(null, null, null, null); + return new AdresssucheResult(Collections.emptyList(), 0, false, null); } - Adressdaten adressdaten = searchOutput.getPersonResult().iterator().next(); - String municipality = adressdaten.getPostAdresse().getGemeinde(); - String village = adressdaten.getPostAdresse().getOrtschaft(); - String street = adressdaten.getPostAdresse().getZustelladresse().getStrassenname(); - String number = adressdaten.getPostAdresse().getZustelladresse().getOrientierungsnummer(); - log.debug("Result from ZMR: '{}', '{}', '{}', '{}'", municipality, village, street, number); - return new AdresssucheOutput(municipality, village, street, number); + boolean moreResults = false; + new HashSet<>(); + log.info("Result level is {}", searchOutput.getLevel()); + Set<AdresssucheOutput> result = searchOutput.getPersonResult().stream() + .map(Adressdaten::getPostAdresse) + .map(it -> new AdresssucheOutput(it.getGemeinde(), it.getOrtschaft(), + it.getZustelladresse().getStrassenname(), it.getZustelladresse().getOrientierungsnummer())) + .collect(Collectors.toSet()); + // TODO Add configuration option for the limit of 30 + List<AdresssucheOutput> sorted = result.stream().sorted().limit(30).collect(Collectors.toList()); + return new AdresssucheResult(sorted, result.size(), moreResults, searchOutput.getLevel().name()); } @NotNull @@ -150,43 +159,32 @@ public class AdresssucheController { return searchInput; } - public static class AdresssucheOutput { + @Data + @AllArgsConstructor + public static class AdresssucheResult { + private final Collection<AdresssucheOutput> results; + private final int resultCount; + private final boolean moreResults; + private final String detailLevel; + + } + + @Data + @AllArgsConstructor + public static class AdresssucheOutput implements Comparable<AdresssucheOutput> { private final String municipality; private final String village; private final String street; private final String number; - public AdresssucheOutput(String municipality, String village, String street, String number) { - this.municipality = municipality; - this.village = village; - this.street = street; - this.number = number; - } - - public String getMunicipality() { - return municipality; - } - - public String getVillage() { - return village; - } - - public String getStreet() { - return street; - } - - public String getNumber() { - return number; - } - @Override - public String toString() { - return "AdresssucheOutput{" + - "municipality='" + municipality + '\'' + - ", village='" + village + '\'' + - ", street='" + street + '\'' + - ", number='" + number + '\'' + - '}'; + public int compareTo(@NotNull AdresssucheOutput o) { + return new CompareToBuilder() + .append(this.municipality, o.municipality) + .append(this.village, o.village) + .append(this.street, o.street) + .append(this.number, o.number) + .toComparison(); } } diff --git a/connector/src/main/resources/templates/residency.html b/connector/src/main/resources/templates/residency.html index 38f490ca..3f0532dd 100644 --- a/connector/src/main/resources/templates/residency.html +++ b/connector/src/main/resources/templates/residency.html @@ -12,24 +12,86 @@ th:attr="src=@{/static/js/jquery-3.6.0.min.js}"></script> <title th:text="#{gui.residency.title}">Österreichischer Wohnsitz</title> <script type="text/javascript" th:inline="javascript"> + $(document).ready(function () { + $("#textResult").hide(); + $("#tableResult").hide(); + $("#loading").hide(); + $.ajaxSetup({ + beforeSend: function () { + $("#loading").show(); + }, + complete: function () { + $("#loading").hide(); + } + }); + }); + function search() { let updatedText = /*[[#{gui.residency.updated}]]*/ 'Updated text'; let errorText = /*[[#{gui.residency.error}]]*/ 'Error'; + let applyText = /*[[#{gui.residency.apply}]]*/ 'Apply'; + let foundText = /*[[#{gui.residency.found}]]*/ 'Found {0}'; + let uniqueText = /*[[#{gui.residency.unique}]]*/ 'Unique'; + let invalidInputText = /*[[#{gui.residency.header.inputinvalid}]]*/ 'Invalid'; + if (!$("#inputForm #inputMunicipality").val().trim() && !$("#inputForm #inputVillage").val().trim()) { + $("#textResult").show().text(invalidInputText); + return; + } $.ajax({ type: "POST", url: "http://localhost:8080/ms_connector/residency/search", data: $("#inputForm").serialize() }).done(function (data, textStatus, jqXHR) { - $("#inputMunicipality").val(data["municipality"]); - $("#inputVillage").val(data["village"]); - $("#inputStreet").val(data["street"]); - $("#inputNumber").val(data["number"]); - $("#textInfo").text(updatedText); + if (data["resultCount"] == 1) { + $("#textResult").show().text(uniqueText); + $("#tableResult tbody").empty(); + $("#tableResult").hide(); + $("#inputForm #inputMunicipality").val(data["results"][0]["municipality"]); + $("#inputForm #inputVillage").val(data["results"][0]["village"]); + $("#inputForm #inputStreet").val(data["results"][0]["street"]); + $("#inputForm #inputNumber").val(data["results"][0]["number"]); + return; + } + $("#textResult").show().text(foundText.replace("{0}", data["resultCount"])); + $("#tableResult").show(); + $("#tableResult tbody").empty(); + $.each(data.results, function (i, output) { + $("#tableResult tbody") + .append($("<tr>") + .append($("<td>").text(output["municipality"] !== null ? output["municipality"] : "")) + .append($("<td>").text(output["village"] !== null ? output["village"] : "")) + .append($("<td>").text(output["street"] !== null ? output["street"] : "")) + .append($("<td>").text(output["number"] !== null ? output["number"] : "")) + .append($("<td>").text(applyText).attr("href", "#").click(function () { + $("#inputForm #inputMunicipality").val($(this).parent().children("td:nth-child(1)").text()); + $("#inputForm #inputVillage").val($(this).parent().children("td:nth-child(2)").text()); + $("#inputForm #inputStreet").val($(this).parent().children("td:nth-child(3)").text()); + $("#inputForm #inputNumber").val($(this).parent().children("td:nth-child(4)").text()); + $("#textResult").show().text(updatedText); + search(); + })) + ); + }) }).fail(function (jqXHR, textStatus, errorThrown) { - $("#textInfo").text(errorText); + $("#textResult").show().text(errorText); }) } + + function clearInput() { + $("#inputForm #inputMunicipality").val(""); + $("#inputForm #inputVillage").val(""); + $("#inputForm #inputStreet").val(""); + $("#inputForm #inputNumber").val(""); + $("#textResult").hide(); + $("#tableResult").hide(); + } </script> + <style> + td { + padding: 0.5em; + margin: 0.5em; + } + </style> </head> <body> @@ -41,38 +103,64 @@ <h2 th:text="#{gui.residency.header.selection}">Search your Austrian Residency</h2> <div id="residency"> - <div> - <p><span id="textInfo">Infotext</span></p> - </div> <form id="inputForm" method="post" action="$contextPath$submitEndpoint" th:attr="action=@{${submitEndpoint}}"> + <div th:text="#{gui.residency.header.help}">Please enter a Municipality or Village first</div> <div> - <label for="inputMunicipality">Municipality</label> - <input type="text" id="inputMunicipality" name="municipality" value="Municipality"/> + <label for="inputMunicipality" th:text="#{gui.residency.input.municipality}">Municipality</label> + <input type="text" id="inputMunicipality" name="municipality" value=""/> </div> <div> - <label for="inputVillage">Village</label> - <input type="text" id="inputVillage" name="village" value="Village"/> + <label for="inputVillage" th:text="#{gui.residency.input.village}">Village</label> + <input type="text" id="inputVillage" name="village" value=""/> </div> <div> - <label for="inputStreet">Street</label> - <input type="text" id="inputStreet" name="street" value="Street"/> + <label for="inputStreet" th:text="#{gui.residency.input.street}">Street</label> + <input type="text" id="inputStreet" name="street" value=""/> </div> <div> - <label for="inputNumber">Number</label> - <input type="text" id="inputNumber" name="number" value="Number"/> + <label for="inputNumber" th:text="#{gui.residency.input.number}">Number</label> + <input type="text" id="inputNumber" name="number" value=""/> </div> <div> <button type="button" class="block" onclick="search()" th:attr="value=#{gui.residency.search}">Search </button> </div> <div> + <button type="button" class="block" onclick="clearInput()" th:attr="value=#{gui.residency.clear}">Clear + </button> + </div> + <div> <button type="button" class="block" th:attr="value=#{gui.residency.proceed}">Proceed</button> </div> + <div> + <img id="loading" src="$contextPath/static/img/ajax-loader.gif" + th:attr="src=@{/static/img/ajax-loader.gif}" /> + </div> <input type="hidden" name="pendingid" value="$pendingid" th:attr="value=${pendingid}"/> </form> </div> + <div id="result"> + <div> + <p><span id="textResult"></span></p> + </div> + <table id="tableResult"> + <thead> + <tr> + <th th:text="#{gui.residency.input.municipality}">Municipality</th> + <th th:text="#{gui.residency.input.village}">Village</th> + <th th:text="#{gui.residency.input.street}">Street</th> + <th th:text="#{gui.residency.input.number}">Number</th> + <th th:text="#{gui.residency.apply}">Apply</th> + </tr> + </thead> + <tbody> + + </tbody> + </table> + </div> + <form class="block" method="post" action="$contextPath$submitEndpoint" th:attr="action=@{${submitEndpoint}}"> <input type="submit" class="btn btn-outline-primary btn-block" value="Abbrechen/Cancel" th:attr="value=#{gui.residency.cancel}"> diff --git a/connector/src/main/webapp/img/ajax-loader.gif b/connector/src/main/webapp/img/ajax-loader.gif Binary files differnew file mode 100644 index 00000000..f2a1bc0c --- /dev/null +++ b/connector/src/main/webapp/img/ajax-loader.gif diff --git a/connector/src/test/resources/config/properties/messages.properties b/connector/src/test/resources/config/properties/messages.properties index 1e0f04d0..51befbfc 100644 --- a/connector/src/test/resources/config/properties/messages.properties +++ b/connector/src/test/resources/config/properties/messages.properties @@ -106,11 +106,18 @@ gui.residency.header1=Federal Ministry of Internal Affairs gui.residency.header2=Austrian Central eIDAS Node gui.residency.header3=Operated by Federal Ministry of Internal Affairs gui.residency.header.selection=Search for your Austrian Residency +gui.residency.header.help=You can search for the address that you have been registered at in the past. Please enter a \ + Municipality or Village first to start the search. +gui.residency.header.inputinvalid=Be sure to enter a value for Municipality or Village gui.residency.cancel=Cancel gui.residency.search=Search +gui.residency.clear=Clear gui.residency.proceed=Proceed gui.residency.updated=Updated your input +gui.residency.found=Found {0} results +gui.residency.unique=Unique result found, please proceed gui.residency.error=Error on Backend Call +gui.residency.apply=Apply gui.residency.input.municipality=Municipality gui.residency.input.village=Village gui.residency.input.street=Street diff --git a/connector/src/test/resources/config/properties/messages_de.properties b/connector/src/test/resources/config/properties/messages_de.properties index e0eea9d1..c67e445f 100644 --- a/connector/src/test/resources/config/properties/messages_de.properties +++ b/connector/src/test/resources/config/properties/messages_de.properties @@ -107,11 +107,18 @@ gui.residency.header1=Bundesministerium für Inneres gui.residency.header2=Zentraler eIDAS Knoten der Republik Österreich gui.residency.header3=Betrieben durch das Bundesministerium für Inneres gui.residency.header.selection=Suche nach Österreichischem Wohnsitz +gui.residency.header.help=Hier können Sie nach einem Wohnsitze in Österreich suchen. Bitte geben Sie zuerst eine \ + Gemeinde oder Ortschaft ein um die Suche zu starten. +gui.residency.header.inputinvalid=Bitte geben Sie einen Wert für Gemeinde oder Ortschaft ein gui.residency.cancel=Abbrechen gui.residency.search=Suche -gui.residency.proceed=Weiter +gui.residency.clear=Löschen +gui.residency.proceed=Fortfahren gui.residency.updated=Eingabe aktualisiert +gui.residency.found={0} Ergebnisse gefunden +gui.residency.unique=Eindeutiges Ergebnis gefunden, bitte fortfahren gui.residency.error=Fehler bei Addresssuche +gui.residency.apply=Übernehmen gui.residency.input.municipality=Gemeinde gui.residency.input.village=Ortschaft gui.residency.input.street=Straße diff --git a/connector/src/test/resources/config/templates/residency.html b/connector/src/test/resources/config/templates/residency.html index 17e21044..77c13fb7 100644 --- a/connector/src/test/resources/config/templates/residency.html +++ b/connector/src/test/resources/config/templates/residency.html @@ -12,24 +12,86 @@ th:attr="src=@{/static/js/jquery-3.6.0.js}"></script> <title th:text="#{gui.residency.title}">Österreichischer Wohnsitz</title> <script type="text/javascript" th:inline="javascript"> + $(document).ready(function () { + $("#textResult").hide(); + $("#tableResult").hide(); + $("#loading").hide(); + $.ajaxSetup({ + beforeSend: function () { + $("#loading").show(); + }, + complete: function () { + $("#loading").hide(); + } + }); + }); + function search() { let updatedText = /*[[#{gui.residency.updated}]]*/ 'Updated text'; let errorText = /*[[#{gui.residency.error}]]*/ 'Error'; + let applyText = /*[[#{gui.residency.apply}]]*/ 'Apply'; + let foundText = /*[[#{gui.residency.found}]]*/ 'Found {0}'; + let uniqueText = /*[[#{gui.residency.unique}]]*/ 'Unique'; + let invalidInputText = /*[[#{gui.residency.header.inputinvalid}]]*/ 'Invalid'; + if (!$("#inputForm #inputMunicipality").val().trim() && !$("#inputForm #inputVillage").val().trim()) { + $("#textResult").show().text(invalidInputText); + return; + } $.ajax({ type: "POST", url: "http://localhost:8080/ms_connector/residency/search", data: $("#inputForm").serialize() }).done(function (data, textStatus, jqXHR) { - $("#inputMunicipality").val(data["municipality"]); - $("#inputVillage").val(data["village"]); - $("#inputStreet").val(data["street"]); - $("#inputNumber").val(data["number"]); - $("#textInfo").text(updatedText); + if (data["resultCount"] == 1) { + $("#textResult").show().text(uniqueText); + $("#tableResult tbody").empty(); + $("#tableResult").hide(); + $("#inputForm #inputMunicipality").val(data["results"][0]["municipality"]); + $("#inputForm #inputVillage").val(data["results"][0]["village"]); + $("#inputForm #inputStreet").val(data["results"][0]["street"]); + $("#inputForm #inputNumber").val(data["results"][0]["number"]); + return; + } + $("#textResult").show().text(foundText.replace("{0}", data["resultCount"])); + $("#tableResult").show(); + $("#tableResult tbody").empty(); + $.each(data.results, function (i, output) { + $("#tableResult tbody") + .append($("<tr>") + .append($("<td>").text(output["municipality"] !== null ? output["municipality"] : "")) + .append($("<td>").text(output["village"] !== null ? output["village"] : "")) + .append($("<td>").text(output["street"] !== null ? output["street"] : "")) + .append($("<td>").text(output["number"] !== null ? output["number"] : "")) + .append($("<td>").text(applyText).attr("href", "#").click(function () { + $("#inputForm #inputMunicipality").val($(this).parent().children("td:nth-child(1)").text()); + $("#inputForm #inputVillage").val($(this).parent().children("td:nth-child(2)").text()); + $("#inputForm #inputStreet").val($(this).parent().children("td:nth-child(3)").text()); + $("#inputForm #inputNumber").val($(this).parent().children("td:nth-child(4)").text()); + $("#textResult").show().text(updatedText); + search(); + })) + ); + }) }).fail(function (jqXHR, textStatus, errorThrown) { - $("#textInfo").text(errorText); + $("#textResult").show().text(errorText); }) } + + function clearInput() { + $("#inputForm #inputMunicipality").val(""); + $("#inputForm #inputVillage").val(""); + $("#inputForm #inputStreet").val(""); + $("#inputForm #inputNumber").val(""); + $("#textResult").hide(); + $("#tableResult").hide(); + } </script> + <style> + td { + padding: 0.5em; + margin: 0.5em; + } + </style> </head> <body> @@ -41,38 +103,64 @@ <h2 th:text="#{gui.residency.header.selection}">Search your Austrian Residency</h2> <div id="residency"> - <div> - <p><span id="textInfo">Infotext</span></p> - </div> <form id="inputForm" method="post" action="$contextPath$submitEndpoint" th:attr="action=@{${submitEndpoint}}"> + <div th:text="#{gui.residency.header.help}">Please enter a Municipality or Village first</div> <div> - <label for="inputMunicipality">Municipality</label> - <input type="text" id="inputMunicipality" name="municipality" value="Municipality"/> + <label for="inputMunicipality" th:text="#{gui.residency.input.municipality}">Municipality</label> + <input type="text" id="inputMunicipality" name="municipality" value=""/> </div> <div> - <label for="inputVillage">Village</label> - <input type="text" id="inputVillage" name="village" value="Village"/> + <label for="inputVillage" th:text="#{gui.residency.input.village}">Village</label> + <input type="text" id="inputVillage" name="village" value=""/> </div> <div> - <label for="inputStreet">Street</label> - <input type="text" id="inputStreet" name="street" value="Street"/> + <label for="inputStreet" th:text="#{gui.residency.input.street}">Street</label> + <input type="text" id="inputStreet" name="street" value=""/> </div> <div> - <label for="inputNumber">Number</label> - <input type="text" id="inputNumber" name="number" value="Number"/> + <label for="inputNumber" th:text="#{gui.residency.input.number}">Number</label> + <input type="text" id="inputNumber" name="number" value=""/> </div> <div> <button type="button" class="block" onclick="search()" th:attr="value=#{gui.residency.search}">Search </button> </div> <div> + <button type="button" class="block" onclick="clearInput()" th:attr="value=#{gui.residency.clear}">Clear + </button> + </div> + <div> <button type="button" class="block" th:attr="value=#{gui.residency.proceed}">Proceed</button> </div> + <div> + <img id="loading" src="$contextPath/static/img/ajax-loader.gif" + th:attr="src=@{/static/img/ajax-loader.gif}" /> + </div> <input type="hidden" name="pendingid" value="$pendingid" th:attr="value=${pendingid}"/> </form> </div> + <div id="result"> + <div> + <p><span id="textResult"></span></p> + </div> + <table id="tableResult"> + <thead> + <tr> + <th th:text="#{gui.residency.input.municipality}">Municipality</th> + <th th:text="#{gui.residency.input.village}">Village</th> + <th th:text="#{gui.residency.input.street}">Street</th> + <th th:text="#{gui.residency.input.number}">Number</th> + <th th:text="#{gui.residency.apply}">Apply</th> + </tr> + </thead> + <tbody> + + </tbody> + </table> + </div> + <form class="block" method="post" action="$contextPath$submitEndpoint" th:attr="action=@{${submitEndpoint}}"> <input type="submit" class="btn btn-outline-primary btn-block" value="Abbrechen/Cancel" th:attr="value=#{gui.residency.cancel}"> diff --git a/connector/src/test/resources/config/webcontent/img/ajax-loader.gif b/connector/src/test/resources/config/webcontent/img/ajax-loader.gif Binary files differnew file mode 100644 index 00000000..f2a1bc0c --- /dev/null +++ b/connector/src/test/resources/config/webcontent/img/ajax-loader.gif |