package application import ( "context" "encoding/json" "fmt" "net/http" "sort" "time" "git.coopgo.io/coopgo-apps/parcoursmob/utils/identification" "git.coopgo.io/coopgo-apps/parcoursmob/utils/sorting" filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/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" mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage" "github.com/coreos/go-oidc/v3/oidc" "github.com/google/uuid" "github.com/gorilla/mux" "github.com/rs/zerolog/log" "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" ) func (h *ApplicationHandler) VehiclesManagementOverview(w http.ResponseWriter, r *http.Request) { //Get Vehicles request := &fleets.GetVehiclesRequest{ Namespaces: []string{"parcoursmob"}, } resp, err := h.services.GRPC.Fleets.GetVehicles(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) } vehicles := []fleetsstorage.Vehicle{} bookings := []fleetsstorage.Booking{} vehicles_map := map[string]fleetsstorage.Vehicle{} for _, vehicle := range resp.Vehicles { if filterVehicle(r, vehicle) { v := vehicle.ToStorageType() vehicleBookings := []fleetsstorage.Booking{} for _, b := range v.Bookings { if b.Status() != fleetsstorage.StatusOld { if deleted, ok := b.Data["Deleted"].(bool); !ok && !deleted { bookings = append(bookings, b) } } if b.Unavailableto.After(time.Now()) { vehicleBookings = append(vehicleBookings, b) } } v.Bookings = vehicleBookings vehicles = append(vehicles, v) vehicles_map[v.ID] = v } } driversMap, _ := h.services.GetBeneficiariesMap() sort.Sort(sorting.VehiclesByLicencePlate(vehicles)) sort.Sort(sorting.BookingsByStartdate(bookings)) h.Renderer.VehiclesManagementOverview(w, r, vehicles, vehicles_map, driversMap, bookings) } func (h *ApplicationHandler) VehiclesManagementBookingsList(w http.ResponseWriter, r *http.Request) { //Get Vehicles request := &fleets.GetVehiclesRequest{ Namespaces: []string{"parcoursmob"}, } resp, err := h.services.GRPC.Fleets.GetVehicles(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) } bookings := []fleetsstorage.Booking{} vehicles_map := map[string]fleetsstorage.Vehicle{} for _, vehicle := range resp.Vehicles { if filterVehicle(r, vehicle) { v := vehicle.ToStorageType() vehicles_map[v.ID] = v // bookings = append(bookings, v.Bookings...) for _, b := range v.Bookings { if v, ok := b.Data["administrator_unavailability"].(bool); !ok || !v { bookings = append(bookings, b) } } } } sort.Sort(sorting.BookingsByStartdate(bookings)) cacheid := uuid.NewString() h.cache.PutWithTTL(cacheid, bookings, 1*time.Hour) driversMap, _ := h.services.GetBeneficiariesMap() h.Renderer.VehiclesManagementBookingsList(w, r, vehicles_map, driversMap, bookings, cacheid) } func (h *ApplicationHandler) VehiclesFleetAdd(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { g := r.Context().Value(identification.GroupKey) if g == nil { w.WriteHeader(http.StatusBadRequest) return } group := g.(storage.Group) if err := r.ParseForm(); err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusBadRequest) return } dataMap := map[string]any{} if v := r.FormValue("name"); v != "" { dataMap["name"] = v } if v := r.FormValue("address"); v != "" { var address map[string]any err := json.Unmarshal([]byte(v), &address) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } dataMap["address"] = address } if v := r.FormValue("informations"); v != "" { dataMap["informations"] = v } if v := r.FormValue("licence_plate"); v != "" { dataMap["licence_plate"] = v } if v := r.FormValue("automatic"); v != "" { dataMap["automatic"] = (v == "on") } if v := r.FormValue("kilometers"); v != "" { dataMap["kilometers"] = v } data, err := structpb.NewValue(dataMap) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } vehicle := &fleets.Vehicle{ Id: uuid.NewString(), Namespace: "parcoursmob", Type: r.FormValue("type"), Administrators: []string{group.ID}, Data: data.GetStructValue(), } request := &fleets.AddVehicleRequest{ Vehicle: vehicle, } _, err = h.services.GRPC.Fleets.AddVehicle(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/vehicles-management/fleet/%s", vehicle.Id), http.StatusFound) return } vehicles_types := h.config.GetStringSlice("modules.fleets.vehicle_types") h.Renderer.VehiclesFleetAdd(w, r, vehicles_types) } func (h *ApplicationHandler) VehiclesFleetDisplay(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) vehicleid := vars["vehicleid"] request := &fleets.GetVehicleRequest{ Vehicleid: vehicleid, } resp, err := h.services.GRPC.Fleets.GetVehicle(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } h.Renderer.VehiclesFleetDisplay(w, r, resp.Vehicle.ToStorageType()) } func filterVehicle(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) VehicleManagementBookingDisplay(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bookingid := vars["bookingid"] booking, err := h.services.GetBooking(bookingid) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } if r.Method == "POST" { r.ParseForm() newbooking, _ := fleets.BookingFromStorageType(&booking) startdate := r.FormValue("startdate") if startdate != "" { newstartdate, _ := time.Parse("2006-01-02", startdate) newbooking.Startdate = timestamppb.New(newstartdate) if newstartdate.Before(newbooking.Unavailablefrom.AsTime()) { newbooking.Unavailablefrom = timestamppb.New(newstartdate) } } enddate := r.FormValue("enddate") if enddate != "" { newenddate, _ := time.Parse("2006-01-02", enddate) newbooking.Enddate = timestamppb.New(newenddate) if newenddate.After(newbooking.Unavailableto.AsTime()) || newenddate.Equal(newbooking.Unavailableto.AsTime()) { newbooking.Unavailableto = timestamppb.New(newenddate.Add(24 * time.Hour)) } } unavailablefrom := r.FormValue("unavailablefrom") if unavailablefrom != "" { newunavailablefrom, _ := time.Parse("2006-01-02", unavailablefrom) newbooking.Unavailablefrom = timestamppb.New(newunavailablefrom) } unavailableto := r.FormValue("unavailableto") if unavailableto != "" { newunavailableto, _ := time.Parse("2006-01-02", unavailableto) newbooking.Unavailableto = timestamppb.New(newunavailableto) } request := &fleets.UpdateBookingRequest{ Booking: newbooking, } _, err := h.services.GRPC.Fleets.UpdateBooking(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } booking = newbooking.ToStorageType() } beneficiary := mobilityaccountsstorage.Account{} if booking.Driver != "" { beneficiaryrequest := &mobilityaccounts.GetAccountRequest{ Id: booking.Driver, } beneficiaryresp, err := h.services.GRPC.MobilityAccounts.GetAccount(context.TODO(), beneficiaryrequest) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } beneficiary = beneficiaryresp.Account.ToStorageType() } grouprequest := &groupsmanagement.GetGroupRequest{ Id: booking.Vehicle.Administrators[0], } groupresp, err := h.services.GRPC.GroupsManagement.GetGroup(context.TODO(), grouprequest) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } alternativerequest := &fleets.GetVehiclesRequest{ Namespaces: []string{"parcoursmob"}, Types: []string{booking.Vehicle.Type}, Administrators: booking.Vehicle.Administrators, AvailabilityFrom: timestamppb.New(booking.Startdate), AvailabilityTo: timestamppb.New(booking.Enddate.Add(24 * time.Hour)), } alternativeresp, err := h.services.GRPC.Fleets.GetVehicles(context.TODO(), alternativerequest) if err != nil { log.Error().Err(err).Msg("") } alternatives := []any{} for _, a := range alternativeresp.Vehicles { alternatives = append(alternatives, a.ToStorageType()) } documents := h.filestorage.List(filestorage.PREFIX_BOOKINGS + "/" + bookingid) file_types_map := h.config.GetStringMapString("storage.files.file_types") h.Renderer.VehicleManagementBookingDisplay(w, r, booking, booking.Vehicle, beneficiary, groupresp.Group.ToStorageType(), documents, file_types_map, alternatives) } func (h ApplicationHandler) VehicleManagementBookingChangeVehicle(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bookingid := vars["bookingid"] r.ParseForm() newvehicle := r.FormValue("vehicle") booking, err := h.services.GetBooking(bookingid) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } booking.Vehicleid = newvehicle b, _ := fleets.BookingFromStorageType(&booking) request := &fleets.UpdateBookingRequest{ Booking: b, } _, err = h.services.GRPC.Fleets.UpdateBooking(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/vehicles-management/bookings/%s", bookingid), http.StatusFound) } func (h ApplicationHandler) VehiclesFleetMakeUnavailable(w http.ResponseWriter, r *http.Request) { // Get Group g := r.Context().Value(identification.GroupKey) if g == nil { log.Error().Msg("no current group") w.WriteHeader(http.StatusInternalServerError) return } current_group := g.(storage.Group) // Get current user ID u := r.Context().Value(identification.IdtokenKey) if u == nil { log.Error().Msg("no current user") w.WriteHeader(http.StatusInternalServerError) return } current_user_token := u.(*oidc.IDToken) // Get current user claims c := r.Context().Value(identification.ClaimsKey) if c == nil { log.Error().Msg("no current user claims") w.WriteHeader(http.StatusInternalServerError) return } current_user_claims := c.(map[string]any) vars := mux.Vars(r) vehicleid := vars["vehicleid"] r.ParseForm() start := r.FormValue("unavailablefrom") end := r.FormValue("unavailableto") comment := r.FormValue("comment") unavailablefrom, _ := time.Parse("2006-01-02", start) unavailableto, _ := time.Parse("2006-01-02", end) data := map[string]any{ "comment": comment, "administrator_unavailability": true, "booked_by": map[string]any{ "user": map[string]any{ "id": current_user_token.Subject, "display_name": current_user_claims["display_name"], }, "group": map[string]any{ "id": current_group.ID, "name": current_group.Data["name"], }, }, } datapb, err := structpb.NewStruct(data) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } booking := &fleets.Booking{ Id: uuid.NewString(), Vehicleid: vehicleid, Unavailablefrom: timestamppb.New(unavailablefrom), Unavailableto: timestamppb.New(unavailableto), Data: datapb, } request := &fleets.CreateBookingRequest{ Booking: booking, } _, err = h.services.GRPC.Fleets.CreateBooking(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusBadRequest) return } http.Redirect(w, r, fmt.Sprintf("/app/vehicles-management/fleet/%s", vehicleid), http.StatusFound) } func (h *ApplicationHandler) UnbookingVehicle(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bookingid := vars["bookingid"] request := &fleets.GetBookingRequest{ Bookingid: bookingid, } resp, err := h.services.GRPC.Fleets.GetBooking(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } now := time.Now() date := now.Format("2006-01-02") unavailableto, _ := time.Parse("2006-01-02", date) current_group, err := h.currentGroup(r) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } current_user_token, current_user_claims, err := h.currentUser(r) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } booked_by_id := resp.Booking.Data.Fields["booked_by"].GetStructValue().Fields["user"].GetStructValue().Fields["id"].GetStringValue() booked_by_name := resp.Booking.Data.Fields["booked_by"].GetStructValue().Fields["user"].GetStructValue().Fields["display_name"].GetStringValue() booked_by_email := resp.Booking.Data.Fields["booked_by"].GetStructValue().Fields["user"].GetStructValue().Fields["email"].GetStringValue() booked_by_group_id := resp.Booking.Data.Fields["booked_by"].GetStructValue().Fields["group"].GetStructValue().Fields["id"].GetStringValue() booked_by_group_name := resp.Booking.Data.Fields["booked_by"].GetStructValue().Fields["group"].GetStructValue().Fields["name"].GetStringValue() data := map[string]any{ "booked_by": map[string]any{ "user": map[string]any{ "id": booked_by_id, "display_name": booked_by_name, "email": booked_by_email, }, "group": map[string]any{ "id": booked_by_group_id, "name": booked_by_group_name, }, }, "unbooked_by": map[string]any{ "user": map[string]any{ "id": current_user_token.Subject, "display_name": current_user_claims["first_name"].(string) + " " + current_user_claims["last_name"].(string), "email": current_user_claims["email"], }, "group": map[string]any{ "id": current_group.ID, "name": current_group.Data["name"], }, }, "Deleted": true, "motif": r.FormValue("motif"), } datapb, err := structpb.NewStruct(data) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } if r.Method == "POST" { request := &fleets.UpdateBookingRequest{ Booking: &fleets.Booking{ Id: resp.Booking.Id, Vehicleid: resp.Booking.Vehicleid, Driver: resp.Booking.Driver, Startdate: resp.Booking.Startdate, Enddate: resp.Booking.Enddate, Unavailablefrom: resp.Booking.Unavailablefrom, Unavailableto: timestamppb.New(unavailableto), Data: datapb, }, } _, err := h.services.GRPC.Fleets.UpdateBooking(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, "/app/vehicles-management/", http.StatusFound) return } h.Renderer.UnbookingVehicle(w, r, resp.Booking.ToStorageType()) } ////////////////////////UpdateVehicle/////////////////////// func (h *ApplicationHandler) VehiclesFleetUpdate(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) vehicleID := vars["vehicleid"] request := &fleets.GetVehicleRequest{ Vehicleid: vehicleID, } resp, err := h.services.GRPC.Fleets.GetVehicle(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } namespaceV := resp.Vehicle.Namespace //typeV := resp.Vehicle.Type administratorsV := resp.Vehicle.Administrators if r.Method == "POST" { fmt.Print(r.FormValue("vehicle_type")) if err := r.ParseForm(); err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusBadRequest) return } dataMap := map[string]any{} if v := r.FormValue("name"); v != "" { dataMap["name"] = v } if v := r.FormValue("address"); v != "" { var address map[string]any err := json.Unmarshal([]byte(v), &address) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } dataMap["address"] = address } if v := r.FormValue("informations"); v != "" { dataMap["informations"] = v } if v := r.FormValue("licence_plate"); v != "" { dataMap["licence_plate"] = v } if v := r.FormValue("kilometers"); v != "" { dataMap["kilometers"] = v } if v := r.FormValue("automatic"); v != "" { dataMap["automatic"] = (v == "on") } data, err := structpb.NewValue(dataMap) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } request := &fleets.UpdateVehicleRequest{ Vehicle: &fleets.Vehicle{ Id: vehicleID, Namespace: namespaceV, Type: r.FormValue("type"), Administrators: administratorsV, Data: data.GetStructValue(), }, } resp, err := h.services.GRPC.Fleets.UpdateVehicle(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/vehicles-management/fleet/%s", resp.Vehicle.Id), http.StatusFound) return } vehicles_types := h.config.GetStringSlice("modules.fleets.vehicle_types") h.Renderer.VehiclesFleetUpdate(w, r, resp.Vehicle.ToStorageType(), vehicles_types) }