package application import ( "context" "encoding/json" "fmt" "net/http" "sort" "strconv" "strings" "time" fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi" groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi" groupstorage "git.coopgo.io/coopgo-platform/groups-management/storage" mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" "github.com/google/uuid" "github.com/gorilla/mux" geojson "github.com/paulmach/go.geojson" "gitlab.scity.coop/maas/navitia-golang" "gitlab.scity.coop/maas/navitia-golang/types" "google.golang.org/protobuf/types/known/structpb" ) var Depart any var Arrive any func (h *ApplicationHandler) JourneysSearch(w http.ResponseWriter, r *http.Request) { r.ParseForm() locTime, errTime := time.LoadLocation("Europe/Paris") if errTime != nil { fmt.Println("Loading timezone location Europe/Paris error : ") fmt.Println("Missing zones in container ? ") panic(errTime) } departuredate := r.FormValue("departuredate") departuretime := r.FormValue("departuretime") departuredatetime, _ := time.ParseInLocation("2006-01-02 15:04", fmt.Sprintf("%s %s", departuredate, departuretime), locTime) departure := r.FormValue("departure") destination := r.FormValue("destination") searched := false var ( departuregeo *geojson.Feature destinationgeo *geojson.Feature journeys *navitia.JourneyResults carpoolresults any vehicles = []any{} ) if departuredate != "" && departuretime != "" && departure != "" && destination != "" { searched = true var err error departuregeo, err = geojson.UnmarshalFeature([]byte(departure)) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusBadRequest) return } destinationgeo, err = geojson.UnmarshalFeature([]byte(destination)) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusBadRequest) return } //TODO make it a library session, _ := navitia.NewCustom( h.config.GetString("services.navitia.api_key"), "https://api.navitia.io/v1", &http.Client{}) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusBadRequest) return } 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])), Date: departuredatetime.Add(-2 * time.Hour), DateIsArrival: false, //TODO } journeys, err = session.Journeys(context.Background(), request) if err != nil { fmt.Println(err) // w.WriteHeader(http.StatusBadRequest) // return } //CARPOOL // carpoolrequest := fmt.Sprintf( // "https://api.rdex.ridygo.fr/journeys.json?p[driver][state]=1&frequency=punctual&p[passenger][state]=0&p[from][latitude]=%f&p[from][longitude]=%f&p[to][latitude]=%f&p[to][longitude]=%f&p[outward][mindate]=%s&p[outward][maxdate]=%s", // departuregeo.Geometry.Point[1], departuregeo.Geometry.Point[0], // destinationgeo.Geometry.Point[1], destinationgeo.Geometry.Point[0], // departuredatetime.Format("2006-01-02"), departuredatetime.Add(24*time.Hour).Format("2006-01-02")) carpoolrequest := "https://api.rdex.ridygo.fr/journeys.json" client := &http.Client{} req, err := http.NewRequest("GET", carpoolrequest, nil) if err != nil { fmt.Println(err) } req.URL.RawQuery = fmt.Sprintf( "p[driver][state]=1&frequency=punctual&p[passenger][state]=0&p[from][latitude]=%f&p[from][longitude]=%f&p[to][latitude]=%f&p[to][longitude]=%f&p[outward][mindate]=%s&p[outward][maxdate]=%s", departuregeo.Geometry.Point[1], departuregeo.Geometry.Point[0], destinationgeo.Geometry.Point[1], destinationgeo.Geometry.Point[0], departuredatetime.Format("2006-01-02"), departuredatetime.Format("2006-01-02")) req.Header.Set("X-API-KEY", "123456") resp, err := client.Do(req) if err != nil { fmt.Println(err) } if err == nil && resp.StatusCode == http.StatusOK { err = json.NewDecoder(resp.Body).Decode(&carpoolresults) if err != nil { fmt.Println(err) } if carpoolresults == nil { carpoolresults = []any{} } } else { carpoolresults = []any{} } // Vehicles vehiclerequest := &fleets.GetVehiclesRequest{ Namespaces: []string{"parcoursmob"}, } vehicleresp, err := h.services.GRPC.Fleets.GetVehicles(context.TODO(), vehiclerequest) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) } for _, vehicle := range vehicleresp.Vehicles { v := vehicle.ToStorageType() if v.Free(departuredatetime.Add(-24*time.Hour), departuredatetime.Add(168*time.Hour)) { vehicles = append(vehicles, v) } } } h.Renderer.JourneysSearch(w, r, carpoolresults, journeys, vehicles, searched, departuregeo, destinationgeo, departuredate, departuretime) } type GroupsModule []groupstorage.Group func (a GroupsModule) Len() int { return len(a) } func (a GroupsModule) Less(i, j int) bool { return strings.Compare(a[i].Data["name"].(string), a[j].Data["name"].(string)) < 0 } func (a GroupsModule) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (h *ApplicationHandler) GroupsGestion(w http.ResponseWriter, r *http.Request) { request := &groupsmanagement.GetGroupsRequest{ Namespaces: []string{"parcoursmob_groups_covoiturage"}, } resp, err := h.services.GRPC.GroupsManagement.GetGroups(context.TODO(), request) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } var groups = []groupstorage.Group{} for _, group := range resp.Groups { g := group.ToStorageType() groups = append(groups, g) } cacheid := uuid.NewString() sort.Sort(GroupsModule(groups)) h.cache.PutWithTTL(cacheid, groups, 1*time.Hour) h.Renderer.GroupsGestion(w, r, groups, cacheid) } func filterAcc(r *http.Request, a *mobilityaccounts.Account) bool { searchFilter, ok := r.URL.Query()["search"] if ok && len(searchFilter[0]) > 0 { name := a.Data.AsMap()["first_name"].(string) + " " + a.Data.AsMap()["last_name"].(string) if !strings.Contains(strings.ToLower(name), strings.ToLower(searchFilter[0])) { return false } } return true } func (h *ApplicationHandler) CreateGroup(w http.ResponseWriter, r *http.Request) { var beneficiary any var ( departurgeo *geojson.Feature dstinationgeo *geojson.Feature ) searched := false if r.FormValue("beneficiaryid") != "" { searched = true requestbeneficiary := &mobilityaccounts.GetAccountRequest{ Id: r.FormValue("beneficiaryid"), } respbeneficiary, err := h.services.GRPC.MobilityAccounts.GetAccount(context.TODO(), requestbeneficiary) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } beneficiary = respbeneficiary.Account.ToStorageType() if r.Method == "POST" { departure := r.FormValue("departure") destination := r.FormValue("destination") if departure != "" && destination != "" { var err error departurgeo, err = geojson.UnmarshalFeature([]byte(departure)) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusBadRequest) return } dstinationgeo, err = geojson.UnmarshalFeature([]byte(destination)) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusBadRequest) return } } if r.FormValue("departure") != "" { var a any json.Unmarshal([]byte(r.FormValue("departure")), &a) Depart = a } if r.FormValue("destination") != "" { var a any json.Unmarshal([]byte(r.FormValue("destination")), &a) Arrive = a } r.ParseForm() if r.FormValue("name") == "" { fmt.Println("invalid name") w.WriteHeader(http.StatusBadRequest) return } if r.FormValue("number") == "" { fmt.Println("invalid number of personne") w.WriteHeader(http.StatusBadRequest) return } planDays := map[string]any{ "lundi": r.FormValue("lundi") == "on", "mardi": r.FormValue("mardi") == "on", "mercredi": r.FormValue("mercredi") == "on", "jeudi": r.FormValue("jeudi") == "on", "vendredi": r.FormValue("vendredi") == "on", "samedi": r.FormValue("samedi") == "on", "dimanche": r.FormValue("dimanche") == "on", } groupidd := uuid.NewString() dataMap := map[string]any{ "name": r.FormValue("name"), "number": r.FormValue("number"), "driver_first_name": respbeneficiary.Account.ToStorageType().Data["first_name"], "driver_last_name": respbeneficiary.Account.ToStorageType().Data["last_name"], "depart": Depart, "arrive": Arrive, "departdate": r.FormValue("departdate"), "date": r.FormValue("date"), "enddate": r.FormValue("enddate"), "departtime": r.FormValue("departtime"), "time": r.FormValue("time"), "planDays": planDays, "recurrent": r.FormValue("recurrent"), "pontuelle": r.FormValue("ponctuelle"), } data, err := structpb.NewValue(dataMap) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } request_organization := &groupsmanagement.AddGroupRequest{ Group: &groupsmanagement.Group{ Id: groupidd, Namespace: "parcoursmob_groups_covoiturage", Data: data.GetStructValue(), }, } _, err = h.services.GRPC.GroupsManagement.AddGroup(context.TODO(), request_organization) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/journeys/groups_covoiturage/create/%s", request_organization.Group.ToStorageType().ID), http.StatusFound) return } } accountsBeneficaire, err := h.beneficiaries(r) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusBadRequest) return } h.Renderer.CreateGroup(w, r, Depart, Arrive, searched, beneficiary, accountsBeneficaire, departurgeo, dstinationgeo) } func (h *ApplicationHandler) DisplayGroupCovoiturage(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) groupid := vars["groupid"] request := &groupsmanagement.GetGroupRequest{ Id: groupid, } resp, err := h.services.GRPC.GroupsManagement.GetGroup(context.TODO(), request) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } var accounts = []any{} requesst := &mobilityaccounts.GetAccountsBatchRequest{ Accountids: resp.Group.Members, } ressp, _ := h.services.GRPC.MobilityAccounts.GetAccountsBatch(context.TODO(), requesst) for _, account := range ressp.Accounts { if filterAcc(r, account) { a := account.ToStorageType() accounts = append(accounts, a) } } cacheid := uuid.NewString() h.cache.PutWithTTL(cacheid, accounts, 1*time.Hour) r.ParseForm() var beneficiary any searched := false if r.FormValue("beneficiaryid") != "" { searched = true requestbeneficiary := &mobilityaccounts.GetAccountRequest{ Id: r.FormValue("beneficiaryid"), } respbeneficiary, err := h.services.GRPC.MobilityAccounts.GetAccount(context.TODO(), requestbeneficiary) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } beneficiary = respbeneficiary.Account.ToStorageType() subscribe := &groupsmanagement.SubscribeRequest{ Groupid: resp.Group.ToStorageType().ID, Memberid: respbeneficiary.Account.Id, } _, err = h.services.GRPC.GroupsManagement.Subscribe(context.TODO(), subscribe) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } /*******************Code to store more information about mermbers groupscovoiturage**************/ if r.FormValue("departure") != "" { var a any json.Unmarshal([]byte(r.FormValue("departure")), &a) Depart = a } if r.FormValue("destination") != "" { var a any json.Unmarshal([]byte(r.FormValue("destination")), &a) Arrive = a } r.ParseForm() dataMap := map[string]any{ "depart": Depart, "arrive": Arrive, } id := uuid.NewString() data, err := structpb.NewValue(dataMap) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } request_organizatio := &groupsmanagement.AddGroupMemberRequest{ Group: &groupsmanagement.GroupMember{ Id: id, Memberid: respbeneficiary.Account.Id, Groupid: resp.Group.ToStorageType().ID, Data: data.GetStructValue(), }, } _, err = h.services.GRPC.GroupsManagement.AddGroupMember(context.TODO(), request_organizatio) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/journeys/groups_covoiturage/create/%s", resp.Group.ToStorageType().ID), http.StatusFound) return } //////////find all groups to store the adresse passenger/////// // grp := &groupsmanagement.GetGroupsBatchMemberRequest{ // Groupids: []string{resp.Group.ToStorageType().ID}, // } // s, err := h.services.GRPC.GroupsManagement.GetGroupsBatchMember(context.TODO(), grp) // if err != nil { // fmt.Println(err) // w.WriteHeader(http.StatusInternalServerError) // return // } // groups := map[string]any{} // if err == nil { // for _, g := range s.Groups { // groups[g.Memberid] = g.ToStorageType() // } // } //////////find all groups to store the adresse passenger/////// ///////////try to optimise the code //////////////////////////// groups, _ := h.services.GetGroupsMemberMap(resp.Group.ToStorageType().ID) //fmt.Println(groups) var number string = strconv.Itoa(len(resp.Group.Members)) ///////////////////// accountsBeneficaire, err := h.beneficiaries(r) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusBadRequest) return } h.Renderer.DisplayGroupCovoiturage(w, r, number, resp.Group.ToStorageType().ID, Depart, Arrive, accounts, cacheid, searched, beneficiary, resp.Group.ToStorageType(), accountsBeneficaire, groups) } func (h *ApplicationHandler) UpdateGroupCovoiturage(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] groupid := vars["groupid"] memberid := vars["memberid"] if r.Method == "POST" { //////////get groupid covoiturage////////// request := &groupsmanagement.GetGroupRequest{ Id: groupid, } resp, err := h.services.GRPC.GroupsManagement.GetGroup(context.TODO(), request) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } //////////////////////////get group member//////////////////////////////// reequest := &groupsmanagement.GetGroupMemberRequest{ Id: id, } ressp, err := h.services.GRPC.GroupsManagement.GetGroupMember(context.TODO(), reequest) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } req := &groupsmanagement.UnsubscribeMemberRequest{ Id: ressp.Group.Id, } _, errr := h.services.GRPC.GroupsManagement.UnsubscribeMember(context.TODO(), req) if errr != nil { fmt.Println(errr) w.WriteHeader(http.StatusInternalServerError) return } members := resp.Group.Members for i := 0; i < len(members); i++ { if members[i] == memberid { members = append(members[:i], members[(i+1):]...) resp.Group.Members = members reequest := &groupsmanagement.UnsubscribeRequest{ Groupid: resp.Group.ToStorageType().ID, Memberid: memberid, } _, err := h.services.GRPC.GroupsManagement.Unsubscribe(context.TODO(), reequest) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusInternalServerError) return } } } http.Redirect(w, r, fmt.Sprintf("/app/journeys/groups_covoiturage/create/%s", groupid), http.StatusFound) /* I must add "return" to resolve the err http: superfluous response.WriteHeader call from git.coopgo.io/coopgo-apps/parcoursmob/renderer.(*Renderer).Render (renderer.go:50) */ return } h.Renderer.UpdateGroupCovoiturage(w, r, groupid, memberid) }