diff --git a/Dockerfile b/Dockerfile index bb7c0c6..f399fe2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,9 @@ COPY . . RUN go mod download && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /server +RUN git clone --depth 1 https://git.coopgo.io/coopgo-apps/parcoursmob-default-theme themes/default +RUN git clone -b spie06 --depth 1 https://git.coopgo.io/coopgo-apps/parcoursmob-default-theme themes/spie06 + FROM scratch COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo diff --git a/handlers/api/export.go b/handlers/api/export.go index 2b343ff..11f5309 100644 --- a/handlers/api/export.go +++ b/handlers/api/export.go @@ -59,15 +59,11 @@ func (h APIHandler) CacheExport(w http.ResponseWriter, r *http.Request) { //fmt.Println(data) for _, v := range data { - fmt.Println(v) fm := map[string]any{} flatten("", v.(map[string]any), fm) - fmt.Println(fm) flatmaps = append(flatmaps, fm) } - fmt.Println(flatmaps) - w.Header().Set("Content-Type", "text/csv") w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=export-%s.csv", cacheid)) c := csv.NewWriter(w) diff --git a/handlers/application/administration.go b/handlers/application/administration.go index b6b85e4..518a2a8 100644 --- a/handlers/application/administration.go +++ b/handlers/application/administration.go @@ -14,6 +14,7 @@ import ( groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi" groupstorage "git.coopgo.io/coopgo-platform/groups-management/storage" accounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" + mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage" "github.com/google/uuid" "github.com/gorilla/mux" "google.golang.org/protobuf/types/known/structpb" @@ -129,28 +130,35 @@ func (h *ApplicationHandler) AdministrationGroupDisplay(w http.ResponseWriter, r return } - members, err := h.members() + // members, err := h.members() + // if err != nil { + // if err != nil { + // fmt.Println(err) + // w.WriteHeader(http.StatusInternalServerError) + // return + // } + // } + + // groupmembers := []any{} + // admins := []any{} + + // 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) + // } + // } + // } + + groupmembers, admins, err := h.groupmembers(groupid) if err != nil { - if err != nil { - fmt.Println(err) - w.WriteHeader(http.StatusInternalServerError) - return - } - } - - groupmembers := []any{} - admins := []any{} - - 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) - } - } + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return } h.Renderer.AdministrationGroupDisplay(w, r, resp.Group.ToStorageType(), groupmembers, admins) @@ -332,3 +340,30 @@ func (h *ApplicationHandler) members() ([]*accounts.Account, error) { 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 { + fmt.Println(err) + 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 +} diff --git a/handlers/application/agenda.go b/handlers/application/agenda.go index 6c20ec5..002f111 100644 --- a/handlers/application/agenda.go +++ b/handlers/application/agenda.go @@ -89,8 +89,6 @@ func (h *ApplicationHandler) AgendaCreateEvent(w http.ResponseWriter, r *http.Re return } - fmt.Println(eventForm) - data, _ := structpb.NewStruct(map[string]any{ "address": eventForm.Address, }) diff --git a/handlers/application/beneficiaries.go b/handlers/application/beneficiaries.go index c0dfb3f..73bd6b8 100644 --- a/handlers/application/beneficiaries.go +++ b/handlers/application/beneficiaries.go @@ -66,7 +66,6 @@ func (h *ApplicationHandler) BeneficiaryCreate(w http.ResponseWriter, r *http.Re } group := g.(storage.Group) - fmt.Println(group) if r.Method == "POST" { diff --git a/handlers/application/journeys.go b/handlers/application/journeys.go index 04d3ee4..108e537 100644 --- a/handlers/application/journeys.go +++ b/handlers/application/journeys.go @@ -26,7 +26,6 @@ func (h *ApplicationHandler) JourneysSearch(w http.ResponseWriter, r *http.Reque departuredate := r.FormValue("departuredate") departuretime := r.FormValue("departuretime") departuredatetime, _ := time.ParseInLocation("2006-01-02 15:04", fmt.Sprintf("%s %s", departuredate, departuretime), locTime) - fmt.Println(departuredatetime) departure := r.FormValue("departure") destination := r.FormValue("destination") @@ -70,7 +69,7 @@ func (h *ApplicationHandler) JourneysSearch(w http.ResponseWriter, r *http.Reque w.WriteHeader(http.StatusBadRequest) return } - fmt.Println(session) + request := navitia.JourneyRequest{ From: types.ID(fmt.Sprintf("%f", departuregeo.Geometry.Point[0]) + ";" + fmt.Sprintf("%f", departuregeo.Geometry.Point[1])), To: types.ID(fmt.Sprintf("%f", destinationgeo.Geometry.Point[0]) + ";" + fmt.Sprintf("%f", destinationgeo.Geometry.Point[1])), @@ -124,8 +123,6 @@ func (h *ApplicationHandler) JourneysSearch(w http.ResponseWriter, r *http.Reque carpoolresults = []any{} } - fmt.Println(carpoolresults) - // Vehicles vehiclerequest := &fleets.GetVehiclesRequest{ diff --git a/handlers/application/vehicles-management.go b/handlers/application/vehicles-management.go index 79dc247..6a5d5b7 100644 --- a/handlers/application/vehicles-management.go +++ b/handlers/application/vehicles-management.go @@ -16,6 +16,8 @@ import ( 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" "github.com/google/uuid" "github.com/gorilla/mux" "google.golang.org/protobuf/types/known/structpb" @@ -123,6 +125,10 @@ func (h *ApplicationHandler) VehiclesFleetAdd(w http.ResponseWriter, r *http.Req if v := r.FormValue("licence_plate"); v != "" { dataMap["licence_plate"] = v } + if v := r.FormValue("automatic"); v != "" { + fmt.Println(v) + dataMap["automatic"] = (v == "on") + } data, err := structpb.NewValue(dataMap) if err != nil { @@ -154,7 +160,9 @@ func (h *ApplicationHandler) VehiclesFleetAdd(w http.ResponseWriter, r *http.Req http.Redirect(w, r, fmt.Sprintf("/app/vehicles-management/fleet/%s", vehicle.Id), http.StatusFound) return } - h.Renderer.VehiclesFleetAdd(w, r) + + 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) { @@ -282,15 +290,21 @@ func (h ApplicationHandler) VehicleManagementBookingDisplay(w http.ResponseWrite booking = newbooking.ToStorageType() } - beneficiaryrequest := &mobilityaccounts.GetAccountRequest{ - Id: booking.Driver, - } + beneficiary := mobilityaccountsstorage.Account{} - beneficiaryresp, err := h.services.GRPC.MobilityAccounts.GetAccount(context.TODO(), beneficiaryrequest) - if err != nil { - fmt.Println(err) - w.WriteHeader(http.StatusInternalServerError) - return + if booking.Driver != "" { + beneficiaryrequest := &mobilityaccounts.GetAccountRequest{ + Id: booking.Driver, + } + + beneficiaryresp, err := h.services.GRPC.MobilityAccounts.GetAccount(context.TODO(), beneficiaryrequest) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + beneficiary = beneficiaryresp.Account.ToStorageType() } grouprequest := &groupsmanagement.GetGroupRequest{ @@ -307,5 +321,88 @@ func (h ApplicationHandler) VehicleManagementBookingDisplay(w http.ResponseWrite 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, beneficiaryresp.Account.ToStorageType(), groupresp.Group.ToStorageType(), documents, file_types_map) + h.Renderer.VehicleManagementBookingDisplay(w, r, booking, booking.Vehicle, beneficiary, groupresp.Group.ToStorageType(), documents, file_types_map) +} + +func (h ApplicationHandler) VehiclesFleetMakeUnavailable(w http.ResponseWriter, r *http.Request) { // Get Group + g := r.Context().Value(identification.GroupKey) + if g == nil { + fmt.Println("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 { + fmt.Println("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 { + fmt.Println("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 { + fmt.Println(err) + 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 { + fmt.Println(err) + w.WriteHeader(http.StatusBadRequest) + return + } + + http.Redirect(w, r, fmt.Sprintf("/app/vehicles-management/fleet/%s", vehicleid), http.StatusFound) } diff --git a/handlers/application/vehicles.go b/handlers/application/vehicles.go index 5c4a501..f9a1d3d 100644 --- a/handlers/application/vehicles.go +++ b/handlers/application/vehicles.go @@ -38,6 +38,9 @@ func (h ApplicationHandler) VehiclesSearch(w http.ResponseWriter, r *http.Reques startdate, _ := time.Parse("2006-01-02", start) enddate, _ := time.Parse("2006-01-02", end) + automatic := (r.FormValue("automatic") == "on") + + administrators := []string{} if r.FormValue("beneficiaryid") != "" { // Handler form @@ -57,8 +60,15 @@ func (h ApplicationHandler) VehiclesSearch(w http.ResponseWriter, r *http.Reques beneficiary = respbeneficiary.Account.ToStorageType() request := &fleets.GetVehiclesRequest{ - Namespaces: []string{"parcoursmob"}, + Namespaces: []string{"parcoursmob"}, + AvailabilityFrom: timestamppb.New(startdate), + AvailabilityTo: timestamppb.New(enddate), } + + if r.FormValue("type") != "" { + request.Types = []string{r.FormValue("type")} + } + resp, err := h.services.GRPC.Fleets.GetVehicles(context.TODO(), request) if err != nil { fmt.Println(err) @@ -67,9 +77,27 @@ func (h ApplicationHandler) VehiclesSearch(w http.ResponseWriter, r *http.Reques for _, vehicle := range resp.Vehicles { v := vehicle.ToStorageType() - if v.Free(startdate, enddate) { - vehicles = append(vehicles, v) + + if r.FormValue("type") == "Voiture" && automatic { + fmt.Println(v.Data["automatic"]) + if auto, ok := v.Data["automatic"].(bool); !ok || !auto { + fmt.Println(v.Data["automatic"]) + continue + } } + + adminfound := false + for _, a := range administrators { + if a == v.Administrators[0] { + adminfound = true + break + } + } + if !adminfound { + administrators = append(administrators, v.Administrators[0]) + } + + vehicles = append(vehicles, v) } beneficiarydocuments = h.filestorage.List(filestorage.PREFIX_BENEFICIARIES + "/" + beneficiary.ID) @@ -81,13 +109,30 @@ func (h ApplicationHandler) VehiclesSearch(w http.ResponseWriter, r *http.Reques w.WriteHeader(http.StatusBadRequest) return } + groups := map[string]any{} + if len(administrators) > 0 { + admingroups, err := h.services.GRPC.GroupsManagement.GetGroupsBatch(context.TODO(), &groupsmanagement.GetGroupsBatchRequest{ + Groupids: administrators, + }) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + for _, g := range admingroups.Groups { + groups[g.Id] = g.ToStorageType() + } + + } sort.Sort(sorting.BeneficiariesByName(accounts)) mandatory_documents := h.config.GetStringSlice("modules.fleets.booking_documents.mandatory") file_types_map := h.config.GetStringMapString("storage.files.file_types") + vehicles_types := h.config.GetStringSlice("modules.fleets.vehicle_types") - h.Renderer.VehiclesSearch(w, r, accounts, searched, vehicles, beneficiary, r.FormValue("startdate"), r.FormValue("enddate"), mandatory_documents, file_types_map, beneficiarydocuments) + h.Renderer.VehiclesSearch(w, r, accounts, searched, vehicles, beneficiary, r.FormValue("startdate"), r.FormValue("enddate"), mandatory_documents, file_types_map, beneficiarydocuments, r.FormValue("type"), automatic, vehicles_types, groups) } func (h ApplicationHandler) Book(w http.ResponseWriter, r *http.Request) { @@ -122,6 +167,17 @@ func (h ApplicationHandler) Book(w http.ResponseWriter, r *http.Request) { vehicleid := vars["vehicleid"] beneficiaryid := vars["beneficiaryid"] + vehicle, err := h.services.GRPC.Fleets.GetVehicle(context.TODO(), &fleets.GetVehicleRequest{ + Vehicleid: vehicleid, + }) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("Vehicle not found")) + w.Write([]byte(err.Error())) + return + } + r.ParseMultipartForm(10 * 1024 * 1024) start := r.FormValue("startdate") @@ -207,6 +263,18 @@ func (h ApplicationHandler) Book(w http.ResponseWriter, r *http.Request) { return } + //NOTIFY GROUP MEMBERS + members, _, err := h.groupmembers(vehicle.Vehicle.Administrators[0]) + if err != nil { + fmt.Println(err) + } else { + for _, m := range members { + h.emailing.Send("fleets.bookings.creation_admin_alert", m.Data["email"].(string), map[string]string{ + "bookingid": booking.Id, + }) + } + } + http.Redirect(w, r, fmt.Sprintf("/app/vehicles/bookings/%s", booking.Id), http.StatusFound) } diff --git a/main.go b/main.go index e01324d..1ee3f87 100644 --- a/main.go +++ b/main.go @@ -93,6 +93,7 @@ func main() { application.HandleFunc("/vehicles-management/", applicationHandler.VehiclesManagementOverview) application.HandleFunc("/vehicles-management/fleet/add", applicationHandler.VehiclesFleetAdd) application.HandleFunc("/vehicles-management/fleet/{vehicleid}", applicationHandler.VehiclesFleetDisplay) + application.HandleFunc("/vehicles-management/fleet/{vehicleid}/unavailability", applicationHandler.VehiclesFleetMakeUnavailable) application.HandleFunc("/vehicles-management/fleet/{vehicleid}/update", applicationHandler.VehiclesFleetUpdate) application.HandleFunc("/vehicles-management/bookings/", applicationHandler.VehiclesManagementBookingsList) application.HandleFunc("/vehicles-management/bookings/{bookingid}", applicationHandler.VehicleManagementBookingDisplay) diff --git a/renderer/administration.go b/renderer/administration.go index 9aa09c4..00c31c3 100644 --- a/renderer/administration.go +++ b/renderer/administration.go @@ -1,6 +1,10 @@ package renderer -import "net/http" +import ( + "net/http" + + mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage" +) const administrationMenu = "administration" @@ -21,7 +25,7 @@ func (renderer *Renderer) AdministrationCreateGroup(w http.ResponseWriter, r *ht renderer.Render("administration", w, r, files, state) } -func (renderer *Renderer) AdministrationGroupDisplay(w http.ResponseWriter, r *http.Request, group any, groupmembers []any, admins []any) { +func (renderer *Renderer) AdministrationGroupDisplay(w http.ResponseWriter, r *http.Request, group any, groupmembers []mobilityaccountsstorage.Account, admins []mobilityaccountsstorage.Account) { files := renderer.ThemeConfig.GetStringSlice("views.administration.display_group.files") state := NewState(r, renderer.ThemeConfig, administrationMenu) state.ViewState = map[string]any{ diff --git a/renderer/vehicle-management.go b/renderer/vehicle-management.go index 3dbd057..d371835 100644 --- a/renderer/vehicle-management.go +++ b/renderer/vehicle-management.go @@ -33,9 +33,12 @@ func (renderer *Renderer) VehiclesManagementBookingsList(w http.ResponseWriter, renderer.Render("fleet overview", w, r, files, state) } -func (renderer *Renderer) VehiclesFleetAdd(w http.ResponseWriter, r *http.Request) { +func (renderer *Renderer) VehiclesFleetAdd(w http.ResponseWriter, r *http.Request, vehicle_types []string) { files := renderer.ThemeConfig.GetStringSlice("views.vehicles_management.fleet_add.files") state := NewState(r, renderer.ThemeConfig, vehiclesmanagementMenu) + state.ViewState = map[string]any{ + "vehicle_types": vehicle_types, + } renderer.Render("fleet add vehicle", w, r, files, state) } diff --git a/renderer/vehicles.go b/renderer/vehicles.go index 945f04a..084c4c7 100644 --- a/renderer/vehicles.go +++ b/renderer/vehicles.go @@ -1,7 +1,6 @@ package renderer import ( - "fmt" "net/http" filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage" @@ -22,16 +21,15 @@ func selectDocumentsDefaults(beneficiarydocuments []filestorage.FileInfo, mandat return res } -func (renderer *Renderer) VehiclesSearch(w http.ResponseWriter, r *http.Request, beneficiaries []mobilityaccountsstorage.Account, searched bool, vehicles []any, beneficiary any, startdate any, enddate any, mandatory_documents []string, file_types_map map[string]string, beneficiarydocuments []filestorage.FileInfo) { +func (renderer *Renderer) VehiclesSearch(w http.ResponseWriter, r *http.Request, beneficiaries []mobilityaccountsstorage.Account, searched bool, vehicles []any, beneficiary any, startdate any, enddate any, mandatory_documents []string, file_types_map map[string]string, beneficiarydocuments []filestorage.FileInfo, selected_type string, automatic bool, vehicles_types []string, admingroups map[string]any) { files := renderer.ThemeConfig.GetStringSlice("views.vehicles.search.files") state := NewState(r, renderer.ThemeConfig, vehiclesMenu) viewstate := map[string]any{ - "beneficiaries": beneficiaries, - "searched": searched, + "beneficiaries": beneficiaries, + "searched": searched, + "vehicles_types": vehicles_types, } - fmt.Println(mandatory_documents) - if searched { viewstate["search"] = map[string]any{ "startdate": startdate, @@ -41,6 +39,9 @@ func (renderer *Renderer) VehiclesSearch(w http.ResponseWriter, r *http.Request, "mandatory_documents": mandatory_documents, "file_types_map": file_types_map, "beneficiary_documents": beneficiarydocuments, + "selected_type": selected_type, + "automatic": automatic, + "admingroups": admingroups, "documents_defaults": selectDocumentsDefaults(beneficiarydocuments, mandatory_documents), } } diff --git a/utils/identification/oidc.go b/utils/identification/oidc.go index 8c15a8c..488546b 100644 --- a/utils/identification/oidc.go +++ b/utils/identification/oidc.go @@ -69,7 +69,6 @@ func NewIdentificationProvider(cfg *viper.Viper, services *services.ServicesHand func (p *IdentificationProvider) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Println("IDP Middleware") session, err := p.SessionsStore.Get(r, "parcoursmob_session") if err != nil { fmt.Println(err) diff --git a/utils/storage/etcd.go b/utils/storage/etcd.go index d7d1f77..14d044d 100644 --- a/utils/storage/etcd.go +++ b/utils/storage/etcd.go @@ -122,7 +122,7 @@ func (s *EtcdHandler) PutWithTTL(k string, v any, duration time.Duration) error ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) _, err = s.Client.KV.Put(ctx, k, string(data), clientv3.WithLease(lease.ID)) cancel() - fmt.Println("?") + if err != nil { fmt.Println(err) return err diff --git a/utils/storage/sessions.go b/utils/storage/sessions.go index 1e977ba..52a1207 100644 --- a/utils/storage/sessions.go +++ b/utils/storage/sessions.go @@ -72,7 +72,7 @@ func (s *SessionStore) New(r *http.Request, name string) (*sessions.Session, err // Save adds a single session to the response. func (s *SessionStore) Save(r *http.Request, w http.ResponseWriter, session *sessions.Session) error { - fmt.Println("Save session") + // Marked for deletion. if session.Options.MaxAge <= 0 { if err := s.delete(r.Context(), session); err != nil { @@ -85,12 +85,12 @@ func (s *SessionStore) Save(r *http.Request, w http.ResponseWriter, session *ses if session.ID == "" { session.ID = strings.TrimRight(base32.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(32)), "=") } - fmt.Println("before save") + if err := s.save(r.Context(), session); err != nil { fmt.Println(err) return err } - fmt.Println("secure cookie") + encoded, err := securecookie.EncodeMulti(session.Name(), session.ID, s.Codecs...) if err != nil { fmt.Println(err) @@ -116,15 +116,11 @@ func (s *SessionStore) save(ctx context.Context, session *sessions.Session) erro m[ks] = v } - fmt.Println("loop finished") - age := session.Options.MaxAge if age == 0 { age = s.DefaultMaxAge } - fmt.Println("before return") - return s.KV.PutWithTTL(s.keyPrefix+session.ID, m, time.Duration(age)*time.Second) }