evol: filter geography on beneficiaries
This commit is contained in:
@@ -31,6 +31,8 @@ import (
|
|||||||
solidaritytransformers "git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/transformers"
|
solidaritytransformers "git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/transformers"
|
||||||
solidaritytypes "git.coopgo.io/coopgo-platform/solidarity-transport/types"
|
solidaritytypes "git.coopgo.io/coopgo-platform/solidarity-transport/types"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/paulmach/orb"
|
||||||
|
"github.com/paulmach/orb/geojson"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"google.golang.org/protobuf/types/known/structpb"
|
"google.golang.org/protobuf/types/known/structpb"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
@@ -41,12 +43,38 @@ type BeneficiariesResult struct {
|
|||||||
CacheID string
|
CacheID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ApplicationHandler) GetBeneficiaries(ctx context.Context, searchFilter string, archivedFilter bool) (*BeneficiariesResult, error) {
|
func (h *ApplicationHandler) GetBeneficiaries(ctx context.Context, searchFilter string, archivedFilter bool, addressGeoLayer, addressGeoCode string) (*BeneficiariesResult, error) {
|
||||||
accounts, err := h.getBeneficiariesWithFilters(ctx, searchFilter, archivedFilter)
|
accounts, err := h.getBeneficiariesWithFilters(ctx, searchFilter, archivedFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply address geography filtering
|
||||||
|
if addressGeoLayer != "" && addressGeoCode != "" {
|
||||||
|
addressPolygons, err := h.loadGeographyPolygon(addressGeoLayer, addressGeoCode)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Msg("failed to load beneficiary address geography filter")
|
||||||
|
} else {
|
||||||
|
filtered := []mobilityaccountsstorage.Account{}
|
||||||
|
for _, account := range accounts {
|
||||||
|
if addr, ok := account.Data["address"]; ok {
|
||||||
|
jsonAddr, err := json.Marshal(addr)
|
||||||
|
if err == nil {
|
||||||
|
addrGeojson, err := geojson.UnmarshalFeature(jsonAddr)
|
||||||
|
if err == nil && addrGeojson.Geometry != nil {
|
||||||
|
if point, ok := addrGeojson.Geometry.(orb.Point); ok {
|
||||||
|
if isPointInGeographies(point, addressPolygons) {
|
||||||
|
filtered = append(filtered, account)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accounts = filtered
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sort.Sort(sorting.BeneficiariesByName(accounts))
|
sort.Sort(sorting.BeneficiariesByName(accounts))
|
||||||
|
|
||||||
cacheID := uuid.NewString()
|
cacheID := uuid.NewString()
|
||||||
|
|||||||
@@ -30,15 +30,25 @@ func (s BeneficiariesListState) JSONWithLimits(a int, b int) template.JS {
|
|||||||
return s.JSON()
|
return s.JSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (renderer *Renderer) BeneficiariesList(w http.ResponseWriter, r *http.Request, accounts []mobilityaccountsstorage.Account, cacheid string, archived bool) {
|
func (renderer *Renderer) BeneficiariesList(w http.ResponseWriter, r *http.Request, accounts []mobilityaccountsstorage.Account, cacheid string, archived bool, enrichedGeoFilters []map[string]string, selectedAddressGeo string) {
|
||||||
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.list.files")
|
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.list.files")
|
||||||
|
|
||||||
|
geoFiltersEnabled := len(enrichedGeoFilters) > 0
|
||||||
|
|
||||||
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
|
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
|
||||||
state.ViewState = BeneficiariesListState{
|
state.ViewState = map[string]any{
|
||||||
Count: len(accounts),
|
"list": BeneficiariesListState{
|
||||||
CacheId: cacheid,
|
Count: len(accounts),
|
||||||
Beneficiaries: accounts,
|
CacheId: cacheid,
|
||||||
Archived: archived,
|
Beneficiaries: accounts,
|
||||||
|
Archived: archived,
|
||||||
|
},
|
||||||
|
"geography_filters_enabled": geoFiltersEnabled,
|
||||||
|
"geography_filters_list": enrichedGeoFilters,
|
||||||
|
"archived": archived,
|
||||||
|
"filters": map[string]any{
|
||||||
|
"beneficiary_address_geo": selectedAddressGeo,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.Render("beneficiaries_list", w, r, files, state)
|
renderer.Render("beneficiaries_list", w, r, files, state)
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
formvalidators "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/form-validators"
|
formvalidators "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/form-validators"
|
||||||
@@ -83,14 +85,64 @@ func (h *Handler) BeneficiariesListHTTPHandler() http.HandlerFunc {
|
|||||||
archivedFilter = true
|
archivedFilter = true
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := h.applicationHandler.GetBeneficiaries(r.Context(), searchFilter, archivedFilter)
|
// Extract beneficiary address geography filter
|
||||||
|
beneficiaryAddressGeo := r.URL.Query().Get("beneficiary_address_geo")
|
||||||
|
addressGeoLayer, addressGeoCode := "", ""
|
||||||
|
if beneficiaryAddressGeo != "" {
|
||||||
|
parts := strings.SplitN(beneficiaryAddressGeo, ":", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
addressGeoLayer, addressGeoCode = parts[0], parts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := h.applicationHandler.GetBeneficiaries(r.Context(), searchFilter, archivedFilter, addressGeoLayer, addressGeoCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("error retrieving beneficiaries")
|
log.Error().Err(err).Msg("error retrieving beneficiaries")
|
||||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.renderer.BeneficiariesList(w, r, result.Accounts, result.CacheID, archivedFilter)
|
// Enrich geography filters with names from geography service
|
||||||
|
var enrichedGeoFilters []map[string]string
|
||||||
|
if h.cfg.GetBool("geography.filters.enabled") {
|
||||||
|
geoFilters := h.cfg.Get("geography.filters.geographies")
|
||||||
|
if geoList, ok := geoFilters.([]any); ok {
|
||||||
|
for _, geoItem := range geoList {
|
||||||
|
if geoMap, ok := geoItem.(map[string]any); ok {
|
||||||
|
layer := ""
|
||||||
|
code := ""
|
||||||
|
if l, ok := geoMap["layer"].(string); ok {
|
||||||
|
layer = l
|
||||||
|
}
|
||||||
|
if c, ok := geoMap["code"].(string); ok {
|
||||||
|
code = c
|
||||||
|
}
|
||||||
|
|
||||||
|
enrichedGeo := map[string]string{
|
||||||
|
"layer": layer,
|
||||||
|
"code": code,
|
||||||
|
"name": code,
|
||||||
|
}
|
||||||
|
|
||||||
|
if layer != "" && code != "" {
|
||||||
|
if geoFeature, err := h.services.Geography.Find(layer, code); err == nil {
|
||||||
|
if name := geoFeature.Properties.MustString("nom"); name != "" {
|
||||||
|
enrichedGeo["name"] = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enrichedGeoFilters = append(enrichedGeoFilters, enrichedGeo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(enrichedGeoFilters, func(i, j int) bool {
|
||||||
|
return enrichedGeoFilters[i]["name"] < enrichedGeoFilters[j]["name"]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
h.renderer.BeneficiariesList(w, r, result.Accounts, result.CacheID, archivedFilter, enrichedGeoFilters, beneficiaryAddressGeo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user