Improve vehicles management

This commit is contained in:
Arnaud Delcasse 2022-11-07 01:24:16 +01:00
parent dc53589e7d
commit 58f5a23d1d
15 changed files with 261 additions and 64 deletions

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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,
})

View File

@ -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" {

View File

@ -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{

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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{

View File

@ -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)
}

View File

@ -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),
}
}

View File

@ -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)

View File

@ -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

View File

@ -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)
}