659 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			659 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
		
			Executable File
		
	
	
package application
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"crypto/rand"
 | 
						|
	"encoding/base64"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"net/http"
 | 
						|
	"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"
 | 
						|
	fleetsstorage "git.coopgo.io/coopgo-platform/fleets/storage"
 | 
						|
	groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi"
 | 
						|
	"git.coopgo.io/coopgo-platform/groups-management/storage"
 | 
						|
	groupstorage "git.coopgo.io/coopgo-platform/groups-management/storage"
 | 
						|
	accounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
 | 
						|
	mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
 | 
						|
	mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage"
 | 
						|
	"github.com/google/uuid"
 | 
						|
	"github.com/rs/zerolog/log"
 | 
						|
	"google.golang.org/protobuf/types/known/structpb"
 | 
						|
)
 | 
						|
 | 
						|
type AdministrationDataResult struct {
 | 
						|
	Accounts      []mobilityaccountsstorage.Account
 | 
						|
	Beneficiaries []mobilityaccountsstorage.Account
 | 
						|
	Groups        []groupstorage.Group
 | 
						|
	Bookings      []fleetsstorage.Booking
 | 
						|
	Events        []agendastorage.Event
 | 
						|
}
 | 
						|
 | 
						|
type AdminVehiclesStatsResult struct {
 | 
						|
	Vehicles []fleetsstorage.Vehicle
 | 
						|
	Bookings []fleetsstorage.Booking
 | 
						|
	Groups   map[string]any
 | 
						|
}
 | 
						|
 | 
						|
type AdminBookingsStatsResult struct {
 | 
						|
	Vehicles         map[string]fleetsstorage.Vehicle
 | 
						|
	Bookings         []fleetsstorage.Booking
 | 
						|
	Groups           map[string]any
 | 
						|
	BeneficiariesMap map[string]any
 | 
						|
}
 | 
						|
 | 
						|
type AdminBeneficiariesStatsResult struct {
 | 
						|
	Beneficiaries []mobilityaccountsstorage.Account
 | 
						|
	CacheID       string
 | 
						|
}
 | 
						|
 | 
						|
type AdminEventsStatsResult struct {
 | 
						|
	Events []agendastorage.Event
 | 
						|
	Groups map[string]any
 | 
						|
}
 | 
						|
 | 
						|
// GetAdministrationData retrieves all data needed for the administration dashboard
 | 
						|
func (h *ApplicationHandler) GetAdministrationData(ctx context.Context) (*AdministrationDataResult, error) {
 | 
						|
	var (
 | 
						|
		wg                                                                                               sync.WaitGroup
 | 
						|
		accounts, beneficiaries                                                                          []mobilityaccountsstorage.Account
 | 
						|
		bookings                                                                                         []fleetsstorage.Booking
 | 
						|
		accountsErr, beneficiariesErr, bookingsErr, groupsResponseErr, eventsResponseErr, groupsBatchErr error
 | 
						|
		groups                                                                                           = []groupstorage.Group{}
 | 
						|
		responses                                                                                        = []agendastorage.Event{}
 | 
						|
		groupsResponse                                                                                   *groupsmanagement.GetGroupsResponse
 | 
						|
		eventsResponse                                                                                   *agenda.GetEventsResponse
 | 
						|
		groupids                                                                                         = []string{}
 | 
						|
	)
 | 
						|
 | 
						|
	// Retrieve accounts in a goroutine
 | 
						|
	wg.Add(1)
 | 
						|
	go func() {
 | 
						|
		defer wg.Done()
 | 
						|
		accounts, accountsErr = h.services.GetAccounts()
 | 
						|
	}()
 | 
						|
 | 
						|
	// Retrieve beneficiaries in a goroutine
 | 
						|
	wg.Add(1)
 | 
						|
	go func() {
 | 
						|
		defer wg.Done()
 | 
						|
		beneficiaries, beneficiariesErr = h.services.GetBeneficiaries()
 | 
						|
	}()
 | 
						|
 | 
						|
	// Retrieve bookings in a goroutine
 | 
						|
	wg.Add(1)
 | 
						|
	go func() {
 | 
						|
		defer wg.Done()
 | 
						|
		bookings, bookingsErr = h.services.GetBookings()
 | 
						|
	}()
 | 
						|
 | 
						|
	// Retrieve groups in a goroutine
 | 
						|
	wg.Add(1)
 | 
						|
	go func() {
 | 
						|
		defer wg.Done()
 | 
						|
		request := &groupsmanagement.GetGroupsRequest{
 | 
						|
			Namespaces: []string{"parcoursmob_organizations"},
 | 
						|
		}
 | 
						|
		groupsResponse, groupsResponseErr = h.services.GRPC.GroupsManagement.GetGroups(ctx, request)
 | 
						|
		if groupsResponseErr == nil {
 | 
						|
			for _, group := range groupsResponse.Groups {
 | 
						|
				g := group.ToStorageType()
 | 
						|
				groups = append(groups, g)
 | 
						|
			}
 | 
						|
			sort.Sort(sorting.GroupsByName(groups))
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	// Retrieve Events in a goroutine
 | 
						|
	wg.Add(1)
 | 
						|
	go func() {
 | 
						|
		defer wg.Done()
 | 
						|
		eventsResponse, eventsResponseErr = h.services.GRPC.Agenda.GetEvents(ctx, &agenda.GetEventsRequest{
 | 
						|
			Namespaces: []string{"parcoursmob_dispositifs"},
 | 
						|
		})
 | 
						|
		if eventsResponseErr == nil {
 | 
						|
			for _, e := range eventsResponse.Events {
 | 
						|
				groupids = append(groupids, e.Owners...)
 | 
						|
				responses = append(responses, e.ToStorageType())
 | 
						|
			}
 | 
						|
			sort.Sort(sorting.EventsByStartdate(responses))
 | 
						|
		}
 | 
						|
	}()
 | 
						|
 | 
						|
	wg.Wait()
 | 
						|
 | 
						|
	// Check for errors
 | 
						|
	if accountsErr != nil || beneficiariesErr != nil || bookingsErr != nil || groupsResponseErr != nil || eventsResponseErr != nil {
 | 
						|
		log.Error().
 | 
						|
			Any("accounts error", accountsErr).
 | 
						|
			Any("beneficiaries error", beneficiariesErr).
 | 
						|
			Any("bookings error", bookingsErr).
 | 
						|
			Any("groups response error", groupsResponseErr).
 | 
						|
			Any("events response error", eventsResponseErr).
 | 
						|
			Any("groups batch error", groupsBatchErr).
 | 
						|
			Msg("Error in retrieving administration data")
 | 
						|
		return nil, fmt.Errorf("error retrieving administration data")
 | 
						|
	}
 | 
						|
 | 
						|
	return &AdministrationDataResult{
 | 
						|
		Accounts:      accounts,
 | 
						|
		Beneficiaries: beneficiaries,
 | 
						|
		Groups:        groups,
 | 
						|
		Bookings:      bookings,
 | 
						|
		Events:        responses,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// CreateAdministrationGroup creates a new administration group
 | 
						|
func (h *ApplicationHandler) CreateAdministrationGroup(ctx context.Context, name string, modules map[string]any) (string, error) {
 | 
						|
	groupid := uuid.NewString()
 | 
						|
 | 
						|
	dataMap := map[string]any{
 | 
						|
		"name":    name,
 | 
						|
		"modules": modules,
 | 
						|
	}
 | 
						|
 | 
						|
	data, err := structpb.NewValue(dataMap)
 | 
						|
	if err != nil {
 | 
						|
		log.Error().Err(err).Msg("Cannot create PB struct from data map")
 | 
						|
		return "", fmt.Errorf("failed to create group data: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	request_organization := &groupsmanagement.AddGroupRequest{
 | 
						|
		Group: &groupsmanagement.Group{
 | 
						|
			Id:        groupid,
 | 
						|
			Namespace: "parcoursmob_organizations",
 | 
						|
			Data:      data.GetStructValue(),
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	request_role := &groupsmanagement.AddGroupRequest{
 | 
						|
		Group: &groupsmanagement.Group{
 | 
						|
			Id:        groupid + ":admin",
 | 
						|
			Namespace: "parcoursmob_roles",
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	// Create organization group
 | 
						|
	_, err = h.services.GRPC.GroupsManagement.AddGroup(ctx, request_organization)
 | 
						|
	if err != nil {
 | 
						|
		log.Error().Err(err).Msg("Issue in Groups management service - AddGroup")
 | 
						|
		return "", fmt.Errorf("failed to create organization group: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	// Create admin role for the organization
 | 
						|
	_, err = h.services.GRPC.GroupsManagement.AddGroup(ctx, request_role)
 | 
						|
	if err != nil {
 | 
						|
		log.Error().Err(err).Msg("Issue in Groups management service - AddGroup")
 | 
						|
		return "", fmt.Errorf("failed to create admin role: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return groupid, nil
 | 
						|
}
 | 
						|
 | 
						|
type AdministrationGroupDataResult struct {
 | 
						|
	Group   groupstorage.Group
 | 
						|
	Members []mobilityaccountsstorage.Account
 | 
						|
	Admins  []mobilityaccountsstorage.Account
 | 
						|
}
 | 
						|
 | 
						|
// GetAdministrationGroupData retrieves data for a specific administration group
 | 
						|
func (h *ApplicationHandler) GetAdministrationGroupData(ctx context.Context, groupID string) (*AdministrationGroupDataResult, error) {
 | 
						|
	request := &groupsmanagement.GetGroupRequest{
 | 
						|
		Id: groupID,
 | 
						|
	}
 | 
						|
 | 
						|
	resp, err := h.services.GRPC.GroupsManagement.GetGroup(ctx, request)
 | 
						|
	if err != nil {
 | 
						|
		log.Error().Err(err).Msg("Issue in Groups management service - GetGroup")
 | 
						|
		return nil, fmt.Errorf("failed to get group: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	groupmembers, admins, err := h.groupmembers(groupID)
 | 
						|
	if err != nil {
 | 
						|
		log.Error().Err(err).Msg("issue retrieving group members")
 | 
						|
		return nil, fmt.Errorf("failed to get group members: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return &AdministrationGroupDataResult{
 | 
						|
		Group:   resp.Group.ToStorageType(),
 | 
						|
		Members: groupmembers,
 | 
						|
		Admins:  admins,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// InviteAdministrationGroupAdmin invites a user as admin to an administration group
 | 
						|
func (h *ApplicationHandler) InviteAdministrationGroupAdmin(ctx context.Context, groupID, username string) error {
 | 
						|
	// Get group info
 | 
						|
	groupResp, err := h.services.GRPC.GroupsManagement.GetGroup(ctx, &groupsmanagement.GetGroupRequest{
 | 
						|
		Id: groupID,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("failed to get group: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	group := groupResp.Group.ToStorageType()
 | 
						|
 | 
						|
	accountresp, err := h.services.GRPC.MobilityAccounts.GetAccountUsername(ctx, &mobilityaccounts.GetAccountUsernameRequest{
 | 
						|
		Username:  username,
 | 
						|
		Namespace: "parcoursmob",
 | 
						|
	})
 | 
						|
 | 
						|
	if err == nil {
 | 
						|
		// Account already exists: adding the existing account to group as admin
 | 
						|
		account := accountresp.Account.ToStorageType()
 | 
						|
		if account.Data["groups"] == nil {
 | 
						|
			account.Data["groups"] = []any{}
 | 
						|
		}
 | 
						|
		account.Data["groups"] = append(account.Data["groups"].([]any), groupID+":admin")
 | 
						|
 | 
						|
		as, err := mobilityaccounts.AccountFromStorageType(&account)
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("failed to convert account: %w", err)
 | 
						|
		}
 | 
						|
 | 
						|
		_, err = h.services.GRPC.MobilityAccounts.UpdateData(ctx, &mobilityaccounts.UpdateDataRequest{
 | 
						|
			Account: as,
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("failed to update account: %w", err)
 | 
						|
		}
 | 
						|
 | 
						|
		data := map[string]any{
 | 
						|
			"group":   group.Data["name"],
 | 
						|
			"baseUrl": h.config.GetString("base_url"),
 | 
						|
		}
 | 
						|
 | 
						|
		if err := h.emailing.Send("onboarding.existing_administrator", username, data); err != nil {
 | 
						|
			log.Warn().Err(err).Msg("failed to send existing admin email")
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		// Create onboarding for new admin
 | 
						|
		onboarding := map[string]any{
 | 
						|
			"username": username,
 | 
						|
			"group":    groupID,
 | 
						|
			"admin":    true,
 | 
						|
		}
 | 
						|
 | 
						|
		b := make([]byte, 16)
 | 
						|
		if _, err := io.ReadFull(rand.Reader, b); err != nil {
 | 
						|
			return fmt.Errorf("failed to generate random key: %w", err)
 | 
						|
		}
 | 
						|
		key := base64.RawURLEncoding.EncodeToString(b)
 | 
						|
 | 
						|
		h.cache.PutWithTTL("onboarding/"+key, onboarding, 72*time.Hour)
 | 
						|
 | 
						|
		data := map[string]any{
 | 
						|
			"group":   group.Data["name"],
 | 
						|
			"key":     key,
 | 
						|
			"baseUrl": h.config.GetString("base_url"),
 | 
						|
		}
 | 
						|
 | 
						|
		if err := h.emailing.Send("onboarding.new_administrator", username, data); err != nil {
 | 
						|
			return fmt.Errorf("failed to send new admin email: %w", err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// InviteAdministrationGroupMember invites a user as member to an administration group
 | 
						|
func (h *ApplicationHandler) InviteAdministrationGroupMember(ctx context.Context, groupID, username string) error {
 | 
						|
	// Get group info
 | 
						|
	groupResp, err := h.services.GRPC.GroupsManagement.GetGroup(ctx, &groupsmanagement.GetGroupRequest{
 | 
						|
		Id: groupID,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("failed to get group: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	group := groupResp.Group.ToStorageType()
 | 
						|
 | 
						|
	accountresp, err := h.services.GRPC.MobilityAccounts.GetAccountUsername(ctx, &mobilityaccounts.GetAccountUsernameRequest{
 | 
						|
		Username:  username,
 | 
						|
		Namespace: "parcoursmob",
 | 
						|
	})
 | 
						|
 | 
						|
	if err == nil {
 | 
						|
		// Account already exists: adding the existing account to group
 | 
						|
		account := accountresp.Account.ToStorageType()
 | 
						|
		if account.Data["groups"] == nil {
 | 
						|
			account.Data["groups"] = []any{}
 | 
						|
		}
 | 
						|
		account.Data["groups"] = append(account.Data["groups"].([]any), groupID)
 | 
						|
 | 
						|
		as, err := mobilityaccounts.AccountFromStorageType(&account)
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("failed to convert account: %w", err)
 | 
						|
		}
 | 
						|
 | 
						|
		_, err = h.services.GRPC.MobilityAccounts.UpdateData(ctx, &mobilityaccounts.UpdateDataRequest{
 | 
						|
			Account: as,
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("failed to update account: %w", err)
 | 
						|
		}
 | 
						|
 | 
						|
		data := map[string]any{
 | 
						|
			"group":   group.Data["name"],
 | 
						|
			"baseUrl": h.config.GetString("base_url"),
 | 
						|
		}
 | 
						|
 | 
						|
		if err := h.emailing.Send("onboarding.existing_member", username, data); err != nil {
 | 
						|
			log.Warn().Err(err).Msg("failed to send existing member email")
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		// Create onboarding for new member
 | 
						|
		onboarding := map[string]any{
 | 
						|
			"username": username,
 | 
						|
			"group":    groupID,
 | 
						|
			"admin":    false,
 | 
						|
		}
 | 
						|
 | 
						|
		b := make([]byte, 16)
 | 
						|
		if _, err := io.ReadFull(rand.Reader, b); err != nil {
 | 
						|
			return fmt.Errorf("failed to generate random key: %w", err)
 | 
						|
		}
 | 
						|
		key := base64.RawURLEncoding.EncodeToString(b)
 | 
						|
 | 
						|
		h.cache.PutWithTTL("onboarding/"+key, onboarding, 72*time.Hour)
 | 
						|
 | 
						|
		data := map[string]any{
 | 
						|
			"group":   group.Data["name"],
 | 
						|
			"key":     key,
 | 
						|
			"baseUrl": h.config.GetString("base_url"),
 | 
						|
		}
 | 
						|
 | 
						|
		if err := h.emailing.Send("onboarding.new_member", username, data); err != nil {
 | 
						|
			return fmt.Errorf("failed to send new member email: %w", err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func filteVehicle(r *http.Request, v *fleets.Vehicle) bool {
 | 
						|
	g := r.Context().Value(identification.GroupKey)
 | 
						|
	if g == nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	group := g.(storage.Group)
 | 
						|
 | 
						|
	for _, n := range v.Administrators {
 | 
						|
		if n == group.ID {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
func (h *ApplicationHandler) GetVehiclesStats() (*AdminVehiclesStatsResult, error) {
 | 
						|
	bookings := []fleetsstorage.Booking{}
 | 
						|
	administrators := []string{}
 | 
						|
	request := &fleets.GetVehiclesRequest{
 | 
						|
		Namespaces: []string{"parcoursmob"},
 | 
						|
	}
 | 
						|
	resp, err := h.services.GRPC.Fleets.GetVehicles(context.TODO(), request)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	vehicles := []fleetsstorage.Vehicle{}
 | 
						|
	for _, vehicle := range resp.Vehicles {
 | 
						|
		v := vehicle.ToStorageType()
 | 
						|
		adminfound := false
 | 
						|
		for _, a := range administrators {
 | 
						|
			if len(v.Administrators) > 0 && a == v.Administrators[0] {
 | 
						|
				adminfound = true
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if !adminfound && len(v.Administrators) > 0 {
 | 
						|
			administrators = append(administrators, v.Administrators[0])
 | 
						|
		}
 | 
						|
 | 
						|
		vehicleBookings := []fleetsstorage.Booking{}
 | 
						|
		for _, b := range v.Bookings {
 | 
						|
			if b.Unavailableto.After(time.Now()) {
 | 
						|
				vehicleBookings = append(vehicleBookings, b)
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		v.Bookings = vehicleBookings
 | 
						|
		vehicles = append(vehicles, v)
 | 
						|
	}
 | 
						|
 | 
						|
	groups := map[string]any{}
 | 
						|
	if len(administrators) > 0 {
 | 
						|
		admingroups, err := h.services.GRPC.GroupsManagement.GetGroupsBatch(context.TODO(), &groupsmanagement.GetGroupsBatchRequest{
 | 
						|
			Groupids: administrators,
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		for _, g := range admingroups.Groups {
 | 
						|
			groups[g.Id] = g.ToStorageType()
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	sort.Sort(sorting.VehiclesByLicencePlate(vehicles))
 | 
						|
	sort.Sort(sorting.BookingsByStartdate(bookings))
 | 
						|
 | 
						|
	return &AdminVehiclesStatsResult{
 | 
						|
		Vehicles: vehicles,
 | 
						|
		Bookings: bookings,
 | 
						|
		Groups:   groups,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *ApplicationHandler) GetBookingsStats(status, startDate, endDate string) (*AdminBookingsStatsResult, error) {
 | 
						|
	vehicles := map[string]fleetsstorage.Vehicle{}
 | 
						|
	bookings := []fleetsstorage.Booking{}
 | 
						|
 | 
						|
	// Parse start date filter
 | 
						|
	var startdate time.Time
 | 
						|
	if startDate != "" {
 | 
						|
		if parsed, err := time.Parse("2006-01-02", startDate); err == nil {
 | 
						|
			startdate = parsed
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Parse end date filter
 | 
						|
	var enddate time.Time
 | 
						|
	if endDate != "" {
 | 
						|
		if parsed, err := time.Parse("2006-01-02", endDate); err == nil {
 | 
						|
			enddate = parsed.Add(24 * time.Hour) // End of day
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	request := &fleets.GetVehiclesRequest{
 | 
						|
		Namespaces:     []string{"parcoursmob"},
 | 
						|
		IncludeDeleted: true,
 | 
						|
	}
 | 
						|
	resp, err := h.services.GRPC.Fleets.GetVehicles(context.TODO(), request)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	beneficiaries_ids := []string{}
 | 
						|
 | 
						|
	for _, vehicle := range resp.Vehicles {
 | 
						|
		v := vehicle.ToStorageType()
 | 
						|
 | 
						|
		for _, b := range v.Bookings {
 | 
						|
			// Apply status filter
 | 
						|
			if status != "" {
 | 
						|
				bookingStatus := b.Status()
 | 
						|
				statusInt := 0
 | 
						|
 | 
						|
				if b.Deleted {
 | 
						|
					statusInt = -2 // Use -2 for cancelled to distinguish from terminated
 | 
						|
				} else {
 | 
						|
					statusInt = bookingStatus
 | 
						|
				}
 | 
						|
 | 
						|
				// Map status string to int
 | 
						|
				var filterStatusInt int
 | 
						|
				switch status {
 | 
						|
				case "FORTHCOMING":
 | 
						|
					filterStatusInt = 1
 | 
						|
				case "ONGOING":
 | 
						|
					filterStatusInt = 0
 | 
						|
				case "TERMINATED":
 | 
						|
					filterStatusInt = -1
 | 
						|
				case "CANCELLED":
 | 
						|
					filterStatusInt = -2
 | 
						|
				default:
 | 
						|
					filterStatusInt = 999 // Invalid status, won't match anything
 | 
						|
				}
 | 
						|
 | 
						|
				if statusInt != filterStatusInt {
 | 
						|
					continue
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			// Apply date filter (on startdate)
 | 
						|
			if !startdate.IsZero() && b.Startdate.Before(startdate) {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			if !enddate.IsZero() && b.Startdate.After(enddate) {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			bookings = append(bookings, b)
 | 
						|
			beneficiaries_ids = append(beneficiaries_ids, b.Driver)
 | 
						|
		}
 | 
						|
 | 
						|
		vehicles[v.ID] = v
 | 
						|
	}
 | 
						|
 | 
						|
	groups := map[string]any{}
 | 
						|
 | 
						|
	admingroups, err := h.services.GRPC.GroupsManagement.GetGroups(context.TODO(), &groupsmanagement.GetGroupsRequest{
 | 
						|
		Namespaces: []string{"parcoursmob_organizations"},
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	for _, g := range admingroups.Groups {
 | 
						|
		groups[g.Id] = g.ToStorageType()
 | 
						|
	}
 | 
						|
 | 
						|
	beneficiaries, err := h.services.GRPC.MobilityAccounts.GetAccountsBatch(context.TODO(), &accounts.GetAccountsBatchRequest{
 | 
						|
		Accountids: beneficiaries_ids,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	beneficiaries_map := map[string]any{}
 | 
						|
	for _, ben := range beneficiaries.Accounts {
 | 
						|
		beneficiaries_map[ben.Id] = ben.ToStorageType()
 | 
						|
	}
 | 
						|
 | 
						|
	return &AdminBookingsStatsResult{
 | 
						|
		Vehicles:         vehicles,
 | 
						|
		Bookings:         bookings,
 | 
						|
		Groups:           groups,
 | 
						|
		BeneficiariesMap: beneficiaries_map,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *ApplicationHandler) GetBeneficiariesStats() (*AdminBeneficiariesStatsResult, error) {
 | 
						|
	beneficiaries, err := h.services.GetBeneficiaries()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	cacheid := uuid.New().String()
 | 
						|
	h.cache.Put(cacheid, beneficiaries)
 | 
						|
 | 
						|
	return &AdminBeneficiariesStatsResult{
 | 
						|
		Beneficiaries: beneficiaries,
 | 
						|
		CacheID:       cacheid,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *ApplicationHandler) GetEventsStats() (*AdminEventsStatsResult, error) {
 | 
						|
	resp, err := h.services.GRPC.Agenda.GetEvents(context.TODO(), &agenda.GetEventsRequest{
 | 
						|
		Namespaces: []string{"parcoursmob_dispositifs"},
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	responses := []agendastorage.Event{}
 | 
						|
	groupids := []string{}
 | 
						|
 | 
						|
	for _, event := range resp.Events {
 | 
						|
		responses = append(responses, event.ToStorageType())
 | 
						|
		groupids = append(groupids, event.Owners...)
 | 
						|
	}
 | 
						|
 | 
						|
	groupsResponse, err := h.services.GRPC.GroupsManagement.GetGroupsBatch(context.TODO(), &groupsmanagement.GetGroupsBatchRequest{
 | 
						|
		Groupids: groupids,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	groups := map[string]any{}
 | 
						|
	for _, g := range groupsResponse.Groups {
 | 
						|
		groups[g.Id] = g.ToStorageType()
 | 
						|
	}
 | 
						|
 | 
						|
	return &AdminEventsStatsResult{
 | 
						|
		Events: responses,
 | 
						|
		Groups: groups,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *ApplicationHandler) members() ([]*accounts.Account, error) {
 | 
						|
	resp, err := h.services.GRPC.MobilityAccounts.GetAccounts(context.TODO(), &accounts.GetAccountsRequest{
 | 
						|
		Namespaces: []string{"parcoursmob"},
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return resp.Accounts, nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *ApplicationHandler) groupmembers(groupid string) (groupmembers []mobilityaccountsstorage.Account, admins []mobilityaccountsstorage.Account, err error) {
 | 
						|
	members, err := h.members()
 | 
						|
	if err != nil {
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("Cannot get members")
 | 
						|
			return nil, nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	groupmembers = []mobilityaccountsstorage.Account{}
 | 
						|
	admins = []mobilityaccountsstorage.Account{}
 | 
						|
 | 
						|
	for _, m := range members {
 | 
						|
		mm := m.ToStorageType()
 | 
						|
		for _, g := range mm.Data["groups"].([]any) {
 | 
						|
			if g.(string) == groupid {
 | 
						|
				groupmembers = append(groupmembers, mm)
 | 
						|
			}
 | 
						|
			if g.(string) == groupid+":admin" {
 | 
						|
				admins = append(admins, mm)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return groupmembers, admins, err
 | 
						|
}
 |