diff --git a/avni-server-api/src/main/java/org/avni/server/dao/LocationRepository.java b/avni-server-api/src/main/java/org/avni/server/dao/LocationRepository.java index c72b2087e..45bbe7b57 100644 --- a/avni-server-api/src/main/java/org/avni/server/dao/LocationRepository.java +++ b/avni-server-api/src/main/java/org/avni/server/dao/LocationRepository.java @@ -150,9 +150,9 @@ default AddressLevel findChildLocation(String title, String type, String parentN return this.findLocationByTitleTypeAndParentName(title, type, parentName); } - AddressLevel findByTitleIgnoreCaseAndTypeNameIgnoreCaseAndIsVoidedFalse(String title, String type); + List findByTitleIgnoreCaseAndTypeNameIgnoreCaseAndIsVoidedFalse(String title, String type); - default AddressLevel findLocation(String title, String type) { + default List findLocation(String title, String type) { return this.findByTitleIgnoreCaseAndTypeNameIgnoreCaseAndIsVoidedFalse(title, type); } diff --git a/avni-server-api/src/main/java/org/avni/server/framework/tomcat/TomcatContainerCustomizer.java b/avni-server-api/src/main/java/org/avni/server/framework/tomcat/TomcatContainerCustomizer.java index b68ee7635..80ca9a765 100644 --- a/avni-server-api/src/main/java/org/avni/server/framework/tomcat/TomcatContainerCustomizer.java +++ b/avni-server-api/src/main/java/org/avni/server/framework/tomcat/TomcatContainerCustomizer.java @@ -1,19 +1,27 @@ package org.avni.server.framework.tomcat; +import org.apache.catalina.Valve; +import org.apache.catalina.valves.AccessLogValve; import org.apache.tomcat.util.http.Rfc6265CookieProcessor; import org.apache.tomcat.util.http.SameSiteCookies; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.stereotype.Component; +import java.util.Collection; + @Component public class TomcatContainerCustomizer implements WebServerFactoryCustomizer { private static final Logger LOGGER = LoggerFactory.getLogger(TomcatContainerCustomizer.class); + @Value("${server.tomcat.accesslog.max-days}") + int accessLogMaxDays; + @Override public void customize(TomcatServletWebServerFactory factory) { if (factory != null) { @@ -23,6 +31,14 @@ public void customize(TomcatServletWebServerFactory factory) { }); factory.addContextCustomizers(sameSiteCookiesConfig()); LOGGER.info("Enabled secure scheme (https)."); + + Collection engineValves = factory.getEngineValves(); + for (Valve tempObject : engineValves) { + if (tempObject instanceof AccessLogValve) { + AccessLogValve accessLogValve = (AccessLogValve) tempObject; + accessLogValve.setMaxDays(accessLogMaxDays); + } + } } else { LOGGER.warn("Could not change protocol scheme because Tomcat is not used as servlet container."); } diff --git a/avni-server-api/src/main/java/org/avni/server/service/AddressLevelService.java b/avni-server-api/src/main/java/org/avni/server/service/AddressLevelService.java index d9a4625d9..18adc857f 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/AddressLevelService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/AddressLevelService.java @@ -15,6 +15,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; import java.util.*; import java.util.stream.Collectors; @@ -146,19 +147,28 @@ public Optional findByAddressMap(Map addressMap) { if (addressMap == null || addressMap.isEmpty()) { return Optional.empty(); } - List addressLevels = addressMap.entrySet().stream().map(entry -> locationRepository.findLocation(entry.getValue(), entry.getKey())) - .filter(Objects::nonNull).sorted(Comparator.comparing(al -> al.getLineage().length())) - .collect(Collectors.toList()); + Set fetchedAddressLevels = addressMap.entrySet().stream().map(entry -> locationRepository.findLocation(entry.getValue(), entry.getKey())) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .sorted(Comparator.comparing(al -> StringUtils.countOccurrencesOf(al.getLineage(), "."))) + .collect(Collectors.toCollection(LinkedHashSet::new)); - if (addressLevels.isEmpty() || addressLevels.size() != addressMap.size()) { - return Optional.empty(); - } + if (fetchedAddressLevels.isEmpty()) return Optional.empty(); + + List addressLevelIds = fetchedAddressLevels.stream().map(AddressLevel::getId).collect(Collectors.toList()); + List addressLevels = fetchedAddressLevels.stream().filter(al -> al.getParentId() == null || addressLevelIds.contains(al.getParentId())).collect(Collectors.toList()); + + if (addressLevels.size() != addressMap.size()) return Optional.empty(); String typeHierarchyForAddressMap = addressLevels.stream().map(al -> String.valueOf(al.getTypeId())).collect(Collectors.joining(".")); + String lineageForAddressMap = addressLevels.stream().map(al -> String.valueOf(al.getId())).collect(Collectors.joining(".")); TreeSet addressLevelTypeHierarchies = locationHierarchyService.fetchAndFilterHierarchies(); - if (addressLevelTypeHierarchies.stream().anyMatch(hierarchy -> hierarchy.contains(typeHierarchyForAddressMap))) { - return Optional.of(addressLevels.get(addressLevels.size() - 1)); + if (addressLevelTypeHierarchies.stream().anyMatch(hierarchy -> hierarchy.equals(typeHierarchyForAddressMap))) { + AddressLevel matchedAddressLevel = addressLevels.get(addressLevels.size() - 1); + if (matchedAddressLevel.getLineage().equals(lineageForAddressMap)) { + return Optional.of(matchedAddressLevel); + } } return Optional.empty(); } diff --git a/avni-server-api/src/main/java/org/avni/server/service/CardService.java b/avni-server-api/src/main/java/org/avni/server/service/CardService.java index 4b871c8d9..12d7b75ae 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/CardService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/CardService.java @@ -168,7 +168,7 @@ public ValueUnit buildDurationForRecentTypeCards(String recentDurationString) { } private void assertNewNameIsUnique(String newName, String oldName) { - if (!newName.equals(oldName)) { + if (!newName.trim().equalsIgnoreCase(oldName.trim())) { assertNoExistingCardWithName(newName); } } diff --git a/avni-server-api/src/main/resources/application.properties b/avni-server-api/src/main/resources/application.properties index 47bfbf90f..dc225e3ee 100644 --- a/avni-server-api/src/main/resources/application.properties +++ b/avni-server-api/src/main/resources/application.properties @@ -133,6 +133,7 @@ avni.keycloak.realm=On-premise server.tomcat.basedir=${OPENCHS_ACCESS_LOG_DIR:.} server.tomcat.accesslog.directory=log server.tomcat.accesslog.enabled=true +server.tomcat.accesslog.max-days=90 #Exotel avni.connectToExotelInDev=${OPENCHS_EXOTEL_IN_DEV:false} diff --git a/avni-server-api/src/main/resources/logback-spring.xml b/avni-server-api/src/main/resources/logback-spring.xml index 5e551addc..4f188f79c 100644 --- a/avni-server-api/src/main/resources/logback-spring.xml +++ b/avni-server-api/src/main/resources/logback-spring.xml @@ -7,6 +7,7 @@ + @@ -15,6 +16,7 @@ + @@ -23,5 +25,6 @@ + diff --git a/avni-server-api/src/test/java/org/avni/server/service/AddressLevelServiceIntegrationTest.java b/avni-server-api/src/test/java/org/avni/server/service/AddressLevelServiceIntegrationTest.java index ea565f2fa..972194dc0 100644 --- a/avni-server-api/src/test/java/org/avni/server/service/AddressLevelServiceIntegrationTest.java +++ b/avni-server-api/src/test/java/org/avni/server/service/AddressLevelServiceIntegrationTest.java @@ -13,7 +13,9 @@ import org.springframework.test.context.jdbc.Sql; import java.util.Arrays; +import java.util.HashMap; import java.util.Map; +import java.util.Optional; import static org.junit.Assert.assertEquals; @@ -45,4 +47,57 @@ public void getTitleLineages() { assertEquals("karnataka, bangalore", titleLineages.get(bangalore.getId())); assertEquals("kerala, kochi", titleLineages.get(kochi.getId())); } + + @Test + public void findByAddressMap() { + testDataSetupService.setupOrganisation(); + AddressLevelType grandParent = addressLevelTypeRepository.save(new AddressLevelTypeBuilder().withUuid("GP").name("GP").level(3d).build()); + AddressLevelType parent = addressLevelTypeRepository.save(new AddressLevelTypeBuilder().withUuid("Parent").name("Parent").parent(grandParent).level(2d).build()); + AddressLevelType child = addressLevelTypeRepository.save(new AddressLevelTypeBuilder().withUuid("Child").name("Child").parent(parent).level(1d).build()); + + AddressLevel gp1AddressLevel = testLocationService.save(new AddressLevelBuilder().withUuid("gp1").title("gp1").type(grandParent).build()); + AddressLevel parent1AddressLevel = testLocationService.save(new AddressLevelBuilder().withUuid("parent1").title("parent1").type(parent).parent(gp1AddressLevel).build()); + AddressLevel child1AddressLevel = testLocationService.save(new AddressLevelBuilder().withUuid("child1").title("child1").type(child).parent(parent1AddressLevel).build()); + AddressLevel gp2AddressLevel = testLocationService.save(new AddressLevelBuilder().withUuid("gp2").title("gp2").type(grandParent).build()); + AddressLevel parent2AddressLevel = testLocationService.save(new AddressLevelBuilder().withUuid("parent2").title("parent2").type(parent).parent(gp2AddressLevel).build()); + AddressLevel child2AddressLevel = testLocationService.save(new AddressLevelBuilder().withUuid("child2").title("child2").type(child).parent(parent2AddressLevel).build()); + AddressLevel gp3AddressLevel = testLocationService.save(new AddressLevelBuilder().withUuid("gp3").title("gp3").type(grandParent).build()); + AddressLevel parent3AddressLevel = testLocationService.save(new AddressLevelBuilder().withUuid("parent3").title("parent2").type(parent).parent(gp3AddressLevel).build()); + AddressLevel child3AddressLevel = testLocationService.save(new AddressLevelBuilder().withUuid("child3").title("child1").type(child).parent(parent3AddressLevel).build()); + + Map addressLevelMap = new HashMap<>(); + + //valid hierarchy + addressLevelMap.put(parent.getName(), parent1AddressLevel.getTitle()); + addressLevelMap.put(child.getName(), child1AddressLevel.getTitle()); + addressLevelMap.put(grandParent.getName(), gp1AddressLevel.getTitle()); + assertEquals(child1AddressLevel, addressLevelService.findByAddressMap(addressLevelMap).get()); + + //valid locations in valid hierarchy but not related + addressLevelMap.put(grandParent.getName(), gp2AddressLevel.getTitle()); + assertEquals(Optional.empty(), addressLevelService.findByAddressMap(addressLevelMap)); + addressLevelMap.put(child.getName(), child2AddressLevel.getTitle()); + assertEquals(Optional.empty(), addressLevelService.findByAddressMap(addressLevelMap)); + + addressLevelMap.put(parent.getName(), parent2AddressLevel.getTitle()); + assertEquals(child2AddressLevel, addressLevelService.findByAddressMap(addressLevelMap).get()); + + //case insensitive + addressLevelMap.remove(parent.getName()); + addressLevelMap.put(parent.getName().toUpperCase(), parent2AddressLevel.getTitle().toUpperCase()); + assertEquals(child2AddressLevel, addressLevelService.findByAddressMap(addressLevelMap).get()); + + //partial hierarchy + addressLevelMap.remove(grandParent.getName()); + assertEquals(Optional.empty(), addressLevelService.findByAddressMap(addressLevelMap)); + + //valid locations in valid hierarchy and related, but with duplicate title + addressLevelMap.put(grandParent.getName(), gp3AddressLevel.getTitle()); + assertEquals(Optional.empty(), addressLevelService.findByAddressMap(addressLevelMap)); + addressLevelMap.remove(parent.getName().toUpperCase()); + addressLevelMap.put(parent.getName(), parent3AddressLevel.getTitle()); + assertEquals(Optional.empty(), addressLevelService.findByAddressMap(addressLevelMap)); + addressLevelMap.put(child.getName(), child3AddressLevel.getTitle()); + assertEquals(child3AddressLevel, addressLevelService.findByAddressMap(addressLevelMap).get()); + } } diff --git a/avni-server-api/src/test/resources/application.properties b/avni-server-api/src/test/resources/application.properties index 73612d1a0..ef4e26caf 100644 --- a/avni-server-api/src/test/resources/application.properties +++ b/avni-server-api/src/test/resources/application.properties @@ -18,6 +18,9 @@ spring.datasource.tomcat.jdbc-interceptors=org.avni.server.framework.tomcat.SetO spring.flyway.schemas=public spring.flyway.baseline-on-migrate=false +#Tomcat +server.tomcat.accesslog.max-days=90 + # JPA, Hibernate and Spring Data spring.jpa.show-sql=false spring.jpa.hibernate.ddl-auto=none