Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
src/main/resources/META-INF/resources/resources/css/jquery*
</sonar.exclusions>
<sonar.coverage.exclusions>
**/infrastructure/api/dto/**Response.*,
**/models/**/*.*,
**/config/**/*.*,
**/*Exception.*,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,12 @@ body .ui-tabs .ui-tabs-panels .ui-tabs-panel {
font-weight: 500;
}

body .ui-autocomplete-panel .ui-autocomplete-items .ui-autocomplete-item.ui-state-highlight {
background: var(--siamois-green-light-200);
color: var(--text-main);

}

body .ui-menuitem-link {
display: flex;
gap: 0.3em;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,8 @@
}

.ui-autocomplete-items .ui-autocomplete-item.ui-state-highlight {
background: var(--siamois-green-light-350);
background: var(--siamois-green-light-200);
color: var(--text-main);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ protected ActionUnitForm() {
.isSystemField(true)
.id(3L)
.valueBinding("spatialContext")
.source("GEOPLAT")
.concept(SPATIAL_CONTEXT_CONCEPT)
.build();

Expand Down Expand Up @@ -162,6 +163,7 @@ protected ActionUnitForm() {
.label("common.label.mainLocation")
.isSystemField(true)
.id(10L)
.source("INSEE")
.valueBinding("mainLocation")
.concept(MAIN_LOCATION_CONCEPT)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

Expand All @@ -14,7 +16,10 @@
@DiscriminatorValue("SELECT_MULTIPLE_SPATIAL_UNIT_TREE")
@Table(name = "custom_field")
@SuperBuilder
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class CustomFieldSelectMultipleSpatialUnitTree extends CustomField {

private String source;

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
Expand All @@ -16,7 +17,9 @@
@Table(name = "custom_field")
@SuperBuilder
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class CustomFieldSelectOneSpatialUnit extends CustomField {

private String source;

}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ public SpatialUnit (SpatialUnit spatialUnit) {
@ColumnTransformer(write = "?::jsonb")
public FullAddress address;

@Column(name = "code")
public String code;

@ManyToMany(mappedBy = "spatialContext")
@JsonIgnore
private Set<ActionUnit> relatedActionUnitList = new HashSet<>();
Expand Down Expand Up @@ -147,6 +150,14 @@ public int hashCode() {
.vocabulary(SYSTEM_THESO)
.externalId("4285848")
.build();

@Transient
@JsonIgnore
public static final Concept CODE_CONCEPT = new Concept.Builder()
.vocabulary(SYSTEM_THESO)
.externalId("")
.build();

// address
@Transient
@JsonIgnore
Expand Down Expand Up @@ -184,6 +195,16 @@ public int hashCode() {
.concept(NAME_CONCEPT)
.build();

@Transient
@JsonIgnore
public static final CustomFieldText CODE_FIELD = CustomFieldText.builder()
.label("common.label.code")
.isSystemField(true)
.id(9L)
.valueBinding("code")
.concept(CODE_CONCEPT)
.build();

@Transient
@JsonIgnore
public static final CustomFieldSelectOneAddress ADDRESS_FIELD = CustomFieldSelectOneAddress.builder()
Expand Down Expand Up @@ -252,6 +273,12 @@ public int hashCode() {
.className(COLUMN_CLASS_NAME)
.field(SPATIAL_UNIT_TYPE_FIELD)
.build())
.addColumn(new CustomCol.Builder()
.readOnly(true)
.isRequired(false)
.className(COLUMN_CLASS_NAME)
.field(CODE_FIELD)
.build())
.addColumn(new CustomCol.Builder()
.readOnly(false)
.isRequired(false)
Expand Down
63 changes: 63 additions & 0 deletions src/main/java/fr/siamois/domain/services/GeoApiService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package fr.siamois.domain.services;

import fr.siamois.domain.models.vocabulary.Concept;
import fr.siamois.domain.services.vocabulary.ConceptService;
import fr.siamois.dto.PlaceSuggestionDTO;
import fr.siamois.dto.entity.ConceptDTO;
import fr.siamois.infrastructure.api.dto.geoapi.CommuneListResponse;
import fr.siamois.mapper.ConceptMapper;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.util.Collections;
import java.util.List;

@AllArgsConstructor
@Service
public class GeoApiService {

private final ConceptService conceptService;
private final ConceptMapper conceptMapper;

private static final String BASE_URL = "https://geo.api.gouv.fr/communes";

private final RestTemplate restTemplate;

public List<PlaceSuggestionDTO> fetchCommunes(String input) {
if (input == null || input.trim().length() < 3) {
return Collections.emptyList();
}

URI uri = UriComponentsBuilder
.fromHttpUrl(BASE_URL)
.queryParam("nom", input)
.queryParam("limit", 10)
.build()
.encode()
.toUri();

CommuneListResponse response = restTemplate.getForObject(uri, CommuneListResponse.class);

if (response == null || response.isEmpty()) {
return Collections.emptyList();
}

// On récupère le concept "Commune" (ID 417) pour typer les résultats externes
Concept communeConcept = conceptService.findById(417).orElse(new Concept());
ConceptDTO conceptDTO = conceptMapper.convert(communeConcept);

return response.stream()
.map(r -> {
PlaceSuggestionDTO dto = new PlaceSuggestionDTO();
dto.setName(r.getNom());
dto.setCategory(conceptDTO);
dto.setCode(r.getCode());
dto.setSourceName("INSEE");
return dto;
})
.toList();
}
}
56 changes: 30 additions & 26 deletions src/main/java/fr/siamois/domain/services/GeoPlatService.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.net.URI;
import java.util.Collections;
import java.util.List;

@AllArgsConstructor
@Service
public class GeoPlatService {
Expand All @@ -20,35 +19,40 @@ public class GeoPlatService {

private final RestTemplate restTemplate = new RestTemplate();

public List<FullAddress> search(String query) {

URI uri = UriComponentsBuilder
.fromHttpUrl(BASE_URL)
.queryParam("text", query)
.queryParam("limit", 10)
.build()
.encode()
.toUri();

GeoPlatResponse response =
restTemplate.getForObject(uri, GeoPlatResponse.class);

if (response == null || response.getResults() == null) {
public List<FullAddress> search(String query) {
try {
URI uri = UriComponentsBuilder
.fromHttpUrl(BASE_URL)
.queryParam("text", query)
.queryParam("maximumResponses", 7)
.queryParam("type", "StreetAddress")
.build()
.encode()
.toUri();

GeoPlatResponse response = restTemplate.getForObject(uri, GeoPlatResponse.class);

if (response == null || response.getResults() == null) {
return Collections.emptyList();
}

return response.getResults().stream()
.map(r -> {
FullAddress a = new FullAddress();
a.setLabel(r.getFulltext());
a.setStreet(r.getStreet());
a.setPostcode(r.getZipcode());
a.setCity(r.getCity());
a.setLon(r.getX());
a.setLat(r.getY());
return a;
})
.toList();
} catch (Exception e) {
return Collections.emptyList();
}

return response.getResults().stream()
.map(r -> {
FullAddress a = new FullAddress();
a.setLabel(r.getFulltext());
a.setStreet(r.getStreet());
a.setPostcode(r.getZipcode());
a.setCity(r.getCity());
a.setLon(r.getX());
a.setLat(r.getY());
return a;
})
.toList();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
import fr.siamois.domain.models.exceptions.actionunit.FailedActionUnitSaveException;
import fr.siamois.domain.models.exceptions.actionunit.NullActionUnitIdentifierException;
import fr.siamois.domain.models.institution.Institution;
import fr.siamois.domain.models.spatialunit.SpatialUnit;
import fr.siamois.domain.models.vocabulary.Concept;
import fr.siamois.domain.services.ArkEntityService;
import fr.siamois.domain.services.vocabulary.ConceptService;
import fr.siamois.dto.entity.*;
import fr.siamois.infrastructure.database.repositories.SpatialUnitRepository;
import fr.siamois.infrastructure.database.repositories.actionunit.ActionCodeRepository;
import fr.siamois.infrastructure.database.repositories.actionunit.ActionUnitRepository;
import fr.siamois.mapper.ActionUnitMapper;
import fr.siamois.mapper.ConceptMapper;
import fr.siamois.mapper.PersonMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -31,10 +34,7 @@

import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;

/**
Expand All @@ -52,6 +52,8 @@ public class ActionUnitService implements ArkEntityService {
private final ActionCodeRepository actionCodeRepository;
private final ActionUnitMapper actionUnitMapper;
private final PersonMapper personMapper;
private final SpatialUnitRepository spatialUnitRepository;
private final ConceptMapper conceptMapper;

/**
* Find all Action Units by institution, name, categories, persons, and global search.
Expand Down Expand Up @@ -142,6 +144,8 @@ public ActionUnit saveNotTransactional(UserInfo info, ActionUnitDTO actionUnitDT
throws ActionUnitAlreadyExistsException {




Optional<ActionUnit> opt = actionUnitRepository.findByNameAndCreatedByInstitutionId(actionUnitDTO.getName(), info.getInstitution().getId());
if (opt.isPresent())
throw new ActionUnitAlreadyExistsException(
Expand Down Expand Up @@ -177,6 +181,47 @@ public ActionUnit saveNotTransactional(UserInfo info, ActionUnitDTO actionUnitDT
Person user = personMapper.invertConvert(info.getUser());
actionUnit.setCreatedBy(user);

if(actionUnitDTO.getMainLocation() != null && actionUnitDTO.getMainLocation().getId() == null) {
SpatialUnit toSave = new SpatialUnit();
toSave.setCategory(actionUnit.getMainLocation().getCategory());
toSave.setName(actionUnitDTO.getMainLocation().getName());
toSave.setCreatedBy(actionUnit.getCreatedBy());
toSave.setCode(actionUnitDTO.getMainLocation().getCode());
toSave.setCreatedByInstitution(actionUnit.getCreatedByInstitution());
toSave = spatialUnitRepository.save(toSave);
actionUnit.setMainLocation(toSave);
}
if (actionUnitDTO.getSpatialContext() != null) {
Set<SpatialUnit> persistentContext = new HashSet<>();

for (SpatialUnitSummaryDTO summary : actionUnitDTO.getSpatialContext()) {
if (summary.getId() == null) {
// CAS : Nouveau lieu (ex: issu de l'API INSEE)
SpatialUnit toSave = new SpatialUnit();
toSave.setName(summary.getName());
toSave.setCode(summary.getCode());
toSave.setCategory(conceptMapper.invertConvert(summary.getCategory()));

// On réutilise les métadonnées de l'unité parente
toSave.setCreatedBy(actionUnit.getCreatedBy());
toSave.setCreatedByInstitution(actionUnit.getCreatedByInstitution());

// Sauvegarde immédiate pour obtenir un ID
toSave = spatialUnitRepository.save(toSave);
persistentContext.add(toSave);
} else {
// CAS : Lieu existant en base
spatialUnitRepository.findById(summary.getId())
.ifPresent(persistentContext::add);
}
}

// Mise à jour de la relation ManyToMany ou OneToMany
actionUnit.setSpatialContext(persistentContext);
}



try {
return actionUnitRepository.save(actionUnit);
} catch (RuntimeException e) {
Expand Down
Loading
Loading