229 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Go
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Go
		
	
	
		
			Executable File
		
	
	
package application
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"sort"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/identification"
 | 
						|
	"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/sorting"
 | 
						|
	agenda "git.coopgo.io/coopgo-platform/agenda/grpcapi"
 | 
						|
	agendastorage "git.coopgo.io/coopgo-platform/agenda/storage"
 | 
						|
	fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi"
 | 
						|
	fleetstorage "git.coopgo.io/coopgo-platform/fleets/storage"
 | 
						|
	"git.coopgo.io/coopgo-platform/groups-management/storage"
 | 
						|
	mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
 | 
						|
	mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage"
 | 
						|
	"github.com/paulmach/orb"
 | 
						|
	"github.com/paulmach/orb/geojson"
 | 
						|
	"github.com/rs/zerolog/log"
 | 
						|
	"google.golang.org/protobuf/types/known/timestamppb"
 | 
						|
)
 | 
						|
 | 
						|
type DashboardResult struct {
 | 
						|
	Accounts                 []mobilityaccountsstorage.Account
 | 
						|
	Members                  []mobilityaccountsstorage.Account
 | 
						|
	Events                   []agendastorage.Event
 | 
						|
	Bookings                 []fleetstorage.Booking
 | 
						|
	SolidarityDrivers        []mobilityaccountsstorage.Account
 | 
						|
	OrganizedCarpoolDrivers  []mobilityaccountsstorage.Account
 | 
						|
}
 | 
						|
 | 
						|
func (h *ApplicationHandler) GetDashboardData(ctx context.Context, driverAddressGeoLayer, driverAddressGeoCode string) (*DashboardResult, error) {
 | 
						|
	g := ctx.Value(identification.GroupKey)
 | 
						|
	if g == nil {
 | 
						|
		return nil, fmt.Errorf("no group found in context")
 | 
						|
	}
 | 
						|
	group := g.(storage.Group)
 | 
						|
 | 
						|
	// Load geography polygons for driver address filtering
 | 
						|
	var driverAddressPolygons []orb.Polygon
 | 
						|
	if driverAddressGeoLayer != "" && driverAddressGeoCode != "" {
 | 
						|
		polygons, err := h.loadGeographyPolygon(driverAddressGeoLayer, driverAddressGeoCode)
 | 
						|
		if err != nil {
 | 
						|
			log.Warn().Err(err).Msg("failed to load driver address geography filter")
 | 
						|
		} else {
 | 
						|
			driverAddressPolygons = polygons
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Get accounts (recent beneficiaries)
 | 
						|
	request := &mobilityaccounts.GetAccountsBatchRequest{
 | 
						|
		Accountids: group.Members,
 | 
						|
	}
 | 
						|
 | 
						|
	resp, err := h.services.GRPC.MobilityAccounts.GetAccountsBatch(ctx, request)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	accounts := []mobilityaccountsstorage.Account{}
 | 
						|
 | 
						|
	// We only display the 5 most recent here
 | 
						|
	count := len(resp.Accounts)
 | 
						|
	min := count - 5
 | 
						|
	if min < 0 {
 | 
						|
		min = 0
 | 
						|
	}
 | 
						|
 | 
						|
	for _, account := range resp.Accounts[min:] {
 | 
						|
		// Check if not archived
 | 
						|
		if archived, ok := account.Data.AsMap()["archived"].(bool); !ok || !archived {
 | 
						|
			a := account.ToStorageType()
 | 
						|
			accounts = append([]mobilityaccountsstorage.Account{a}, accounts...)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Fetch remaining data in parallel using goroutines
 | 
						|
	var wg sync.WaitGroup
 | 
						|
	var mu sync.Mutex
 | 
						|
 | 
						|
	var members []mobilityaccountsstorage.Account
 | 
						|
	var events []agendastorage.Event
 | 
						|
	var bookings []fleetstorage.Booking
 | 
						|
	var solidarityDrivers []mobilityaccountsstorage.Account
 | 
						|
	var organizedCarpoolDrivers []mobilityaccountsstorage.Account
 | 
						|
 | 
						|
	// Get members
 | 
						|
	wg.Add(1)
 | 
						|
	go func() {
 | 
						|
		defer wg.Done()
 | 
						|
		m, _, err := h.groupmembers(group.ID)
 | 
						|
		if err == nil {
 | 
						|
			mu.Lock()
 | 
						|
			members = m
 | 
						|
			mu.Unlock()
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	// Get events
 | 
						|
	wg.Add(1)
 | 
						|
	go func() {
 | 
						|
		defer wg.Done()
 | 
						|
		eventsresp, err := h.services.GRPC.Agenda.GetEvents(ctx, &agenda.GetEventsRequest{
 | 
						|
			Namespaces: []string{"parcoursmob_dispositifs"},
 | 
						|
			Mindate:    timestamppb.Now(),
 | 
						|
		})
 | 
						|
		if err == nil {
 | 
						|
			mu.Lock()
 | 
						|
			for _, e := range eventsresp.Events {
 | 
						|
				events = append(events, e.ToStorageType())
 | 
						|
			}
 | 
						|
			sort.Sort(sorting.EventsByStartdate(events))
 | 
						|
			mu.Unlock()
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	// Get bookings
 | 
						|
	wg.Add(1)
 | 
						|
	go func() {
 | 
						|
		defer wg.Done()
 | 
						|
		bookingsresp, err := h.services.GRPC.Fleets.GetBookings(ctx, &fleets.GetBookingsRequest{
 | 
						|
			Namespaces: []string{"parcoursmob_dispositifs"},
 | 
						|
		})
 | 
						|
		if err == nil {
 | 
						|
			mu.Lock()
 | 
						|
			for _, b := range bookingsresp.Bookings {
 | 
						|
				if b.Enddate.AsTime().After(time.Now()) {
 | 
						|
					bookings = append(bookings, b.ToStorageType())
 | 
						|
				}
 | 
						|
			}
 | 
						|
			mu.Unlock()
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	// Get solidarity transport drivers
 | 
						|
	wg.Add(1)
 | 
						|
	go func() {
 | 
						|
		defer wg.Done()
 | 
						|
		solidarityRequest := &mobilityaccounts.GetAccountsRequest{
 | 
						|
			Namespaces: []string{"solidarity_drivers"},
 | 
						|
		}
 | 
						|
		solidarityResp, err := h.services.GRPC.MobilityAccounts.GetAccounts(ctx, solidarityRequest)
 | 
						|
		if err == nil {
 | 
						|
			mu.Lock()
 | 
						|
			for _, account := range solidarityResp.Accounts {
 | 
						|
				// Only include non-archived drivers with addresses
 | 
						|
				if archived, ok := account.Data.AsMap()["archived"].(bool); !ok || !archived {
 | 
						|
					if address, ok := account.Data.AsMap()["address"]; ok && address != nil {
 | 
						|
						// Apply geography filter if specified
 | 
						|
						if len(driverAddressPolygons) > 0 {
 | 
						|
							if addr, ok := account.Data.AsMap()["address"].(map[string]interface{}); 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, driverAddressPolygons) {
 | 
						|
												solidarityDrivers = append(solidarityDrivers, account.ToStorageType())
 | 
						|
											}
 | 
						|
										}
 | 
						|
									}
 | 
						|
								}
 | 
						|
							}
 | 
						|
						} else {
 | 
						|
							solidarityDrivers = append(solidarityDrivers, account.ToStorageType())
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			mu.Unlock()
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	// Get organized carpool drivers
 | 
						|
	wg.Add(1)
 | 
						|
	go func() {
 | 
						|
		defer wg.Done()
 | 
						|
		carpoolRequest := &mobilityaccounts.GetAccountsRequest{
 | 
						|
			Namespaces: []string{"organized_carpool_drivers"},
 | 
						|
		}
 | 
						|
		carpoolResp, err := h.services.GRPC.MobilityAccounts.GetAccounts(ctx, carpoolRequest)
 | 
						|
		if err == nil {
 | 
						|
			mu.Lock()
 | 
						|
			for _, account := range carpoolResp.Accounts {
 | 
						|
				// Only include non-archived drivers with addresses
 | 
						|
				if archived, ok := account.Data.AsMap()["archived"].(bool); !ok || !archived {
 | 
						|
					if address, ok := account.Data.AsMap()["address"]; ok && address != nil {
 | 
						|
						// Apply geography filter if specified
 | 
						|
						if len(driverAddressPolygons) > 0 {
 | 
						|
							if addr, ok := account.Data.AsMap()["address"].(map[string]interface{}); 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, driverAddressPolygons) {
 | 
						|
												organizedCarpoolDrivers = append(organizedCarpoolDrivers, account.ToStorageType())
 | 
						|
											}
 | 
						|
										}
 | 
						|
									}
 | 
						|
								}
 | 
						|
							}
 | 
						|
						} else {
 | 
						|
							organizedCarpoolDrivers = append(organizedCarpoolDrivers, account.ToStorageType())
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			mu.Unlock()
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	// Wait for all goroutines to complete
 | 
						|
	wg.Wait()
 | 
						|
 | 
						|
	return &DashboardResult{
 | 
						|
		Accounts:                accounts,
 | 
						|
		Members:                 members,
 | 
						|
		Events:                  events,
 | 
						|
		Bookings:                bookings,
 | 
						|
		SolidarityDrivers:       solidarityDrivers,
 | 
						|
		OrganizedCarpoolDrivers: organizedCarpoolDrivers,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 |