423 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
package application
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"net/http"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/identification"
 | 
						|
	groupstorage "git.coopgo.io/coopgo-platform/groups-management/storage"
 | 
						|
	mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage"
 | 
						|
	savedsearchtypes "git.coopgo.io/coopgo-platform/saved-search/data/types"
 | 
						|
	"github.com/gorilla/mux"
 | 
						|
	"github.com/paulmach/orb/geojson"
 | 
						|
	"github.com/rs/zerolog/log"
 | 
						|
)
 | 
						|
 | 
						|
func (h *Handler) JourneysSearchHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		if err := r.ParseForm(); err != nil {
 | 
						|
			log.Error().Err(err).Msg("error parsing form")
 | 
						|
			http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Extract and convert HTTP parameters
 | 
						|
		departureDate := r.FormValue("departuredate")
 | 
						|
		departureTime := r.FormValue("departuretime")
 | 
						|
		departure := r.FormValue("departure")
 | 
						|
		destination := r.FormValue("destination")
 | 
						|
		passengerID := r.FormValue("passengerid")
 | 
						|
		solidarityTransportExcludeDriver := r.FormValue("solidarity_transport_exclude_driver")
 | 
						|
 | 
						|
		// Parse timezone and datetime
 | 
						|
		locTime, err := time.LoadLocation("Europe/Paris")
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("timezone error")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		var departureDateTime time.Time
 | 
						|
		if departureDate != "" && departureTime != "" {
 | 
						|
			departureDateTime, err = time.ParseInLocation("2006-01-02 15:04", departureDate+" "+departureTime, locTime)
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error parsing datetime")
 | 
						|
				http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
				return
 | 
						|
			}
 | 
						|
			log.Info().
 | 
						|
				Str("departureDate", departureDate).
 | 
						|
				Str("departureTime", departureTime).
 | 
						|
				Time("departureDateTime", departureDateTime).
 | 
						|
				Str("timezone", departureDateTime.Location().String()).
 | 
						|
				Str("RFC3339", departureDateTime.Format(time.RFC3339)).
 | 
						|
				Msg("Journey search - parsed departure datetime")
 | 
						|
		}
 | 
						|
 | 
						|
		// Parse departure location
 | 
						|
		var departureGeo *geojson.Feature
 | 
						|
		if departure == "" && passengerID != "" {
 | 
						|
			// Get passenger address
 | 
						|
			p, err := h.services.GetAccount(passengerID)
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("could not retrieve passenger")
 | 
						|
				http.Error(w, "Not Found", http.StatusNotFound)
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			departureBytes, err := json.Marshal(p.Data["address"])
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Any("address", p.Data["address"]).Msg("could not marshal address")
 | 
						|
			} else {
 | 
						|
				departureGeo, err = geojson.UnmarshalFeature(departureBytes)
 | 
						|
				if err != nil {
 | 
						|
					log.Error().Err(err).Msg("error unmarshalling passenger departure")
 | 
						|
					http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
					return
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else if departure != "" {
 | 
						|
			departureGeo, err = geojson.UnmarshalFeature([]byte(departure))
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error unmarshalling departure")
 | 
						|
				http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Parse destination location
 | 
						|
		var destinationGeo *geojson.Feature
 | 
						|
		if destination != "" {
 | 
						|
			destinationGeo, err = geojson.UnmarshalFeature([]byte(destination))
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error unmarshalling destination")
 | 
						|
				http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Call business logic handler
 | 
						|
		result, err := h.applicationHandler.SearchJourneys(
 | 
						|
			r.Context(),
 | 
						|
			departureDateTime,
 | 
						|
			departureGeo,
 | 
						|
			destinationGeo,
 | 
						|
			passengerID,
 | 
						|
			solidarityTransportExcludeDriver,
 | 
						|
			"",  // solidarityExcludeGroupId - for modal search replacement only
 | 
						|
			nil, // options - use defaults
 | 
						|
		)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error in journey search")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Get beneficiaries for rendering
 | 
						|
		g := r.Context().Value(identification.GroupKey)
 | 
						|
		if g == nil {
 | 
						|
			log.Error().Msg("group not found in request context")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
		group := g.(groupstorage.Group)
 | 
						|
 | 
						|
		beneficiaries, err := h.services.GetBeneficiariesInGroup(group)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("issue retrieving beneficiaries")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Get saved searches for this group when no search has been performed
 | 
						|
		var savedSearches []*savedsearchtypes.SavedSearch
 | 
						|
		var beneficiariesMap map[string]mobilityaccountsstorage.Account
 | 
						|
		if !result.Searched {
 | 
						|
			savedSearches, err = h.applicationHandler.GetSavedSearchesByOwner(r.Context(), group.ID)
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("issue retrieving saved searches")
 | 
						|
				// Don't fail the request, just log the error
 | 
						|
				savedSearches = []*savedsearchtypes.SavedSearch{}
 | 
						|
			}
 | 
						|
 | 
						|
			// Create beneficiaries map for template lookup
 | 
						|
			beneficiariesMap = make(map[string]mobilityaccountsstorage.Account)
 | 
						|
			for _, b := range beneficiaries {
 | 
						|
				beneficiariesMap[b.ID] = b
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Render HTTP response
 | 
						|
		h.renderer.JourneysSearch(
 | 
						|
			w, r,
 | 
						|
			result.CarpoolResults,
 | 
						|
			result.TransitResults,
 | 
						|
			result.VehicleResults,
 | 
						|
			result.Searched,
 | 
						|
			departureGeo,
 | 
						|
			destinationGeo,
 | 
						|
			departureDate,
 | 
						|
			departureTime,
 | 
						|
			result.DriverJourneys,
 | 
						|
			result.Drivers,
 | 
						|
			result.OrganizedCarpools,
 | 
						|
			beneficiaries,
 | 
						|
			result.KnowledgeBaseResults,
 | 
						|
			passengerID,
 | 
						|
			savedSearches,
 | 
						|
			beneficiariesMap,
 | 
						|
		)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SaveSearchHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		if err := r.ParseForm(); err != nil {
 | 
						|
			log.Error().Err(err).Msg("error parsing form")
 | 
						|
			http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Extract search parameters from URL query
 | 
						|
		query := r.URL.Query()
 | 
						|
		departureDate := query.Get("departuredate")
 | 
						|
		departureTime := query.Get("departuretime")
 | 
						|
		departure := query.Get("departure")
 | 
						|
		destination := query.Get("destination")
 | 
						|
		passengerID := query.Get("passengerid")
 | 
						|
 | 
						|
		// Debug logging
 | 
						|
		log.Debug().
 | 
						|
			Str("departuredate", departureDate).
 | 
						|
			Str("departuretime", departureTime).
 | 
						|
			Str("departure", departure).
 | 
						|
			Str("destination", destination).
 | 
						|
			Str("passengerid", passengerID).
 | 
						|
			Str("query", r.URL.RawQuery).
 | 
						|
			Msg("SaveSearch request parameters")
 | 
						|
 | 
						|
		// Parse timezone and datetime
 | 
						|
		locTime, err := time.LoadLocation("Europe/Paris")
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("timezone error")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		var departureDateTime time.Time
 | 
						|
		if departureDate != "" && departureTime != "" {
 | 
						|
			departureDateTime, err = time.ParseInLocation("2006-01-02 15:04", departureDate+" "+departureTime, locTime)
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error parsing datetime")
 | 
						|
				http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Parse departure location
 | 
						|
		var departureGeo *geojson.Feature
 | 
						|
		if departure != "" {
 | 
						|
			departureGeo, err = geojson.UnmarshalFeature([]byte(departure))
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error unmarshalling departure")
 | 
						|
				http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Parse destination location
 | 
						|
		var destinationGeo *geojson.Feature
 | 
						|
		if destination != "" {
 | 
						|
			destinationGeo, err = geojson.UnmarshalFeature([]byte(destination))
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error unmarshalling destination")
 | 
						|
				http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Get group ID from session/context
 | 
						|
		g := r.Context().Value(identification.GroupKey)
 | 
						|
		if g == nil {
 | 
						|
			log.Error().Msg("group not found in request context")
 | 
						|
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
 | 
						|
			return
 | 
						|
		}
 | 
						|
		group := g.(groupstorage.Group)
 | 
						|
 | 
						|
		// Prepare additional data
 | 
						|
		additionalData := map[string]interface{}{}
 | 
						|
		if passengerID != "" {
 | 
						|
			additionalData["passenger_id"] = passengerID
 | 
						|
		}
 | 
						|
 | 
						|
		// Save the search using the business logic
 | 
						|
		err = h.applicationHandler.SaveSearch(
 | 
						|
			r.Context(),
 | 
						|
			group.ID,
 | 
						|
			departureDateTime,
 | 
						|
			departureGeo,
 | 
						|
			destinationGeo,
 | 
						|
			additionalData,
 | 
						|
		)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error saving search")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Redirect back to search with success message
 | 
						|
		http.Redirect(w, r, "/app/journeys/", http.StatusSeeOther)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) DeleteSavedSearchHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		// Get search ID from URL parameters
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		searchID := vars["id"]
 | 
						|
		if searchID == "" {
 | 
						|
			log.Error().Msg("search ID not provided")
 | 
						|
			http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Get group ID from session/context for authorization
 | 
						|
		g := r.Context().Value(identification.GroupKey)
 | 
						|
		if g == nil {
 | 
						|
			log.Error().Msg("group not found in request context")
 | 
						|
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
 | 
						|
			return
 | 
						|
		}
 | 
						|
		group := g.(groupstorage.Group)
 | 
						|
 | 
						|
		// Delete the saved search using the business logic
 | 
						|
		err := h.applicationHandler.DeleteSavedSearch(r.Context(), searchID, group.ID)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Str("search_id", searchID).Msg("error deleting saved search")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		log.Info().Str("search_id", searchID).Str("group_id", group.ID).Msg("saved search deleted successfully")
 | 
						|
 | 
						|
		// Redirect back to journeys page
 | 
						|
		http.Redirect(w, r, "/app/journeys/?deleted=1", http.StatusSeeOther)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) JourneysSearchCompactHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		if err := r.ParseForm(); err != nil {
 | 
						|
			log.Error().Err(err).Msg("error parsing form")
 | 
						|
			http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Extract and convert HTTP parameters (same as JourneysSearchHTTPHandler)
 | 
						|
		departureDate := r.FormValue("departuredate")
 | 
						|
		departureTime := r.FormValue("departuretime")
 | 
						|
		departure := r.FormValue("departure")
 | 
						|
		destination := r.FormValue("destination")
 | 
						|
		passengerID := r.FormValue("passengerid")
 | 
						|
		solidarityTransportExcludeDriver := r.FormValue("solidarity_transport_exclude_driver")
 | 
						|
 | 
						|
		// Parse timezone and datetime
 | 
						|
		locTime, err := time.LoadLocation("Europe/Paris")
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("timezone error")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		var departureDateTime time.Time
 | 
						|
		if departureDate != "" && departureTime != "" {
 | 
						|
			departureDateTime, err = time.ParseInLocation("2006-01-02 15:04", departureDate+" "+departureTime, locTime)
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error parsing datetime")
 | 
						|
				http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Parse departure location
 | 
						|
		var departureGeo *geojson.Feature
 | 
						|
		if departure == "" && passengerID != "" {
 | 
						|
			// Get passenger address
 | 
						|
			p, err := h.services.GetAccount(passengerID)
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("could not retrieve passenger")
 | 
						|
				http.Error(w, "Not Found", http.StatusNotFound)
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			departureBytes, err := json.Marshal(p.Data["address"])
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Any("address", p.Data["address"]).Msg("could not marshal address")
 | 
						|
			} else {
 | 
						|
				departureGeo, err = geojson.UnmarshalFeature(departureBytes)
 | 
						|
				if err != nil {
 | 
						|
					log.Error().Err(err).Msg("error unmarshalling passenger departure")
 | 
						|
					http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
					return
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else if departure != "" {
 | 
						|
			departureGeo, err = geojson.UnmarshalFeature([]byte(departure))
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error unmarshalling departure")
 | 
						|
				http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Parse destination location
 | 
						|
		var destinationGeo *geojson.Feature
 | 
						|
		if destination != "" {
 | 
						|
			destinationGeo, err = geojson.UnmarshalFeature([]byte(destination))
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error unmarshalling destination")
 | 
						|
				http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Call business logic handler
 | 
						|
		result, err := h.applicationHandler.SearchJourneys(
 | 
						|
			r.Context(),
 | 
						|
			departureDateTime,
 | 
						|
			departureGeo,
 | 
						|
			destinationGeo,
 | 
						|
			passengerID,
 | 
						|
			solidarityTransportExcludeDriver,
 | 
						|
			"",  // solidarityExcludeGroupId - for modal search replacement only
 | 
						|
			nil, // options - use defaults
 | 
						|
		)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error in journey search")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Render compact HTTP response
 | 
						|
		h.renderer.JourneysSearchCompact(
 | 
						|
			w, r,
 | 
						|
			result.CarpoolResults,
 | 
						|
			result.TransitResults,
 | 
						|
			result.VehicleResults,
 | 
						|
			result.Searched,
 | 
						|
			departureGeo,
 | 
						|
			destinationGeo,
 | 
						|
			departureDate,
 | 
						|
			departureTime,
 | 
						|
			result.DriverJourneys,
 | 
						|
			result.Drivers,
 | 
						|
			result.OrganizedCarpools,
 | 
						|
			result.KnowledgeBaseResults,
 | 
						|
			passengerID,
 | 
						|
		)
 | 
						|
	}
 | 
						|
}
 | 
						|
 |