Add documents

This commit is contained in:
Arnaud Delcasse 2022-11-01 00:40:20 +01:00
parent f4c2d61dc3
commit 0dd4a723be
24 changed files with 687 additions and 65 deletions

14
go.mod
View File

@ -6,7 +6,7 @@ go 1.18
// replace git.coopgo.io/coopgo-platform/groups-management => ../../coopgo-platform/groups-management/
// replace git.coopgo.io/coopgo-platform/fleets => ../../coopgo-platform/fleets/
replace git.coopgo.io/coopgo-platform/fleets => ../../coopgo-platform/fleets/
// replace git.coopgo.io/coopgo-platform/agenda => ../../coopgo-platform/agenda/
@ -40,6 +40,7 @@ require (
require (
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
@ -49,17 +50,26 @@ require (
github.com/golang/snappy v0.0.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mb0/wkt v0.0.0-20170420051526-a30afd545ee1 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.43 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pquerna/cachecontrol v0.1.0 // indirect
github.com/rs/xid v1.4.0 // indirect
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect

24
go.sum
View File

@ -95,6 +95,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@ -222,6 +223,8 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
@ -230,6 +233,12 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -256,14 +265,23 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mb0/wkt v0.0.0-20170420051526-a30afd545ee1 h1:VCgV+ng800r1/AChRHzHbWCtQI06cPxoZQUljQHTyXc=
github.com/mb0/wkt v0.0.0-20170420051526-a30afd545ee1/go.mod h1:IhobDa5AIyiMAsnH/qkytD0NbG0JMOJ2ihQqe1NdXyg=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.43 h1:14Q4lwblqTdlAmba05oq5xL0VBLHi06zS4yLnIkz6hI=
github.com/minio/minio-go/v7 v7.0.43/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@ -310,12 +328,16 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 h1:TToq11gyfNlrMFZiYujSekIsPd9AmsA2Bj/iv+s4JHE=
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
@ -550,6 +572,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

View File

@ -37,20 +37,15 @@ func (h APIHandler) OAuth2Callback(w http.ResponseWriter, r *http.Request) {
redirect := "/app/"
if session.Values["redirect"] != nil && session.Values["redirect"] != "" {
fmt.Println("no redirect stuff")
redirect = session.Values["redirect"].(string)
delete(session.Values, "redirect")
}
if err = session.Save(r, w); err != nil {
fmt.Println(err)
panic(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
fmt.Println(session.Values)
fmt.Println("redirect")
http.Redirect(w, r, redirect, http.StatusFound)
}

View File

@ -11,22 +11,24 @@ import (
)
type ApplicationHandler struct {
config *viper.Viper
Renderer *renderer.Renderer
services *services.ServicesHandler
cache cache.CacheHandler
emailing *emailing.Mailer
config *viper.Viper
Renderer *renderer.Renderer
services *services.ServicesHandler
cache cache.CacheHandler
filestorage cache.FileStorage
emailing *emailing.Mailer
}
func NewApplicationHandler(cfg *viper.Viper, svc *services.ServicesHandler, cache cache.CacheHandler, emailing *emailing.Mailer) (*ApplicationHandler, error) {
func NewApplicationHandler(cfg *viper.Viper, svc *services.ServicesHandler, cache cache.CacheHandler, filestorage cache.FileStorage, emailing *emailing.Mailer) (*ApplicationHandler, error) {
templates_root := cfg.GetString("templates.root")
renderer := renderer.NewRenderer(cfg, templates_root)
return &ApplicationHandler{
config: cfg,
Renderer: renderer,
services: svc,
cache: cache,
emailing: emailing,
config: cfg,
Renderer: renderer,
services: svc,
cache: cache,
filestorage: filestorage,
emailing: emailing,
}, nil
}

View File

@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"image/png"
"io"
"log"
"net/http"
"sort"
@ -17,6 +18,7 @@ import (
formvalidators "git.coopgo.io/coopgo-apps/parcoursmob/utils/form-validators"
"git.coopgo.io/coopgo-apps/parcoursmob/utils/identification"
profilepictures "git.coopgo.io/coopgo-apps/parcoursmob/utils/profile-pictures"
filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage"
fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi"
groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi"
"git.coopgo.io/coopgo-platform/groups-management/storage"
@ -128,6 +130,8 @@ func (h *ApplicationHandler) BeneficiaryDisplay(w http.ResponseWriter, r *http.R
vars := mux.Vars(r)
beneficiaryID := vars["beneficiaryid"]
documents := h.filestorage.List(filestorage.PREFIX_BENEFICIARIES + "/" + beneficiaryID)
request := &mobilityaccounts.GetAccountRequest{
Id: beneficiaryID,
}
@ -158,7 +162,10 @@ func (h *ApplicationHandler) BeneficiaryDisplay(w http.ResponseWriter, r *http.R
bookings = append(bookings, b.ToStorageType())
}
h.Renderer.BeneficiaryDisplay(w, r, resp.Account.ToStorageType(), bookings)
beneficiaries_file_types := h.config.GetStringSlice("modules.beneficiaries.documents_types")
file_types_map := h.config.GetStringMapString("storage.files.file_types")
h.Renderer.BeneficiaryDisplay(w, r, resp.Account.ToStorageType(), bookings, beneficiaries_file_types, file_types_map, documents)
}
func (h *ApplicationHandler) BeneficiaryUpdate(w http.ResponseWriter, r *http.Request) {
@ -252,6 +259,63 @@ func (h *ApplicationHandler) BeneficiaryPicture(w http.ResponseWriter, r *http.R
}
}
func (h *ApplicationHandler) BeneficiaryDocuments(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
beneficiaryID := vars["beneficiaryid"]
//r.ParseForm()
r.ParseMultipartForm(10 * 1024 * 1024)
document_type := r.FormValue("type")
document_name := r.FormValue("name")
file, header, err := r.FormFile("file-upload")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
fileid := uuid.NewString()
metadata := map[string]string{
"type": document_type,
"name": document_name,
}
if err := h.filestorage.Put(file, filestorage.PREFIX_BENEFICIARIES, fmt.Sprintf("%s/%s_%s", beneficiaryID, fileid, header.Filename), header.Size, metadata); err != nil {
fmt.Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
http.Redirect(w, r, fmt.Sprintf("/app/beneficiaries/%s", beneficiaryID), http.StatusFound)
}
func (h *ApplicationHandler) BeneficiaryDocumentDownload(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
beneficiaryID := vars["beneficiaryid"]
document := vars["document"]
file, info, err := h.filestorage.Get(filestorage.PREFIX_BENEFICIARIES, fmt.Sprintf("%s/%s", beneficiaryID, document))
if err != nil {
fmt.Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", info.ContentType)
if _, err = io.Copy(w, file); err != nil {
fmt.Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
http.Redirect(w, r, fmt.Sprintf("/app/beneficiaries/%s", beneficiaryID), http.StatusFound)
}
func filterAccount(r *http.Request, a *mobilityaccounts.Account) bool {
searchFilter, ok := r.URL.Query()["search"]

View File

@ -5,10 +5,13 @@ import (
"encoding/json"
"fmt"
"net/http"
"sort"
"time"
"git.coopgo.io/coopgo-apps/parcoursmob/utils/identification"
"git.coopgo.io/coopgo-apps/parcoursmob/utils/sorting"
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"
@ -29,15 +32,58 @@ func (h *ApplicationHandler) VehiclesManagementOverview(w http.ResponseWriter, r
w.WriteHeader(http.StatusInternalServerError)
}
var vehicles = []any{}
vehicles := []fleetsstorage.Vehicle{}
bookings := []fleetsstorage.Booking{}
vehicles_map := map[string]fleetsstorage.Vehicle{}
for _, vehicle := range resp.Vehicles {
if filterVehicle(r, vehicle) {
v := vehicle.ToStorageType()
vehicles = append(vehicles, v)
vehicles_map[v.ID] = v
for _, b := range v.Bookings {
if b.Status() != fleetsstorage.StatusOld {
bookings = append(bookings, b)
}
}
}
}
h.Renderer.VehiclesManagementOverview(w, r, vehicles)
sort.Sort(sorting.VehiclesByLicencePlate(vehicles))
sort.Sort(sorting.BookingsByStartdate(bookings))
h.Renderer.VehiclesManagementOverview(w, r, vehicles, vehicles_map, 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 {
fmt.Println(err)
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...)
}
}
sort.Sort(sorting.BookingsByStartdate(bookings))
cacheid := uuid.NewString()
h.cache.PutWithTTL(cacheid, bookings, 1*time.Hour)
h.Renderer.VehiclesManagementBookingsList(w, r, vehicles_map, bookings, cacheid)
}
func (h *ApplicationHandler) VehiclesFleetAdd(w http.ResponseWriter, r *http.Request) {

View File

@ -38,6 +38,8 @@ func main() {
panic(err)
}
filestorage, err := cache.NewFileStorage(cfg)
idp, err := identification.NewIdentificationProvider(cfg, svc, kv)
if err != nil {
panic(err)
@ -49,7 +51,7 @@ func main() {
}
apiHandler, _ := api.NewAPIHandler(cfg, idp, svc, kv)
applicationHandler, _ := application.NewApplicationHandler(cfg, svc, kv, emailing)
applicationHandler, _ := application.NewApplicationHandler(cfg, svc, kv, filestorage, emailing)
authHandler, _ := auth.NewAuthHandler(cfg, idp, svc, kv, emailing)
fmt.Println("Running", service_name, ":")
@ -78,6 +80,8 @@ func main() {
application.HandleFunc("/beneficiaries/create", applicationHandler.BeneficiaryCreate)
application.HandleFunc("/beneficiaries/{beneficiaryid}", applicationHandler.BeneficiaryDisplay)
application.HandleFunc("/beneficiaries/{beneficiaryid}/update", applicationHandler.BeneficiaryUpdate)
application.HandleFunc("/beneficiaries/{beneficiaryid}/documents", applicationHandler.BeneficiaryDocuments)
application.HandleFunc("/beneficiaries/{beneficiaryid}/documents/{document}", applicationHandler.BeneficiaryDocumentDownload)
application.HandleFunc("/beneficiaries/{beneficiaryid}/picture", applicationHandler.BeneficiaryPicture)
application.HandleFunc("/members/{beneficiaryid}/picture", applicationHandler.BeneficiaryPicture)
application.HandleFunc("/journeys/", applicationHandler.JourneysSearch)
@ -89,6 +93,7 @@ func main() {
application.HandleFunc("/vehicles-management/fleet/add", applicationHandler.VehiclesFleetAdd)
application.HandleFunc("/vehicles-management/fleet/{vehicleid}", applicationHandler.VehiclesFleetDisplay)
application.HandleFunc("/vehicles-management/fleet/{vehicleid}/update", applicationHandler.VehiclesFleetUpdate)
application.HandleFunc("/vehicles-management/bookings/", applicationHandler.VehiclesManagementBookingsList)
application.HandleFunc("/vehicles-management/bookings/{bookingid}", applicationHandler.VehicleManagementBookingDisplay)
application.HandleFunc("/agenda/", applicationHandler.AgendaHome)
application.HandleFunc("/agenda/create-event", applicationHandler.AgendaCreateEvent)

View File

@ -52,12 +52,15 @@ type BeneficiariesDisplayState struct {
Beneficiary any
}
func (renderer *Renderer) BeneficiaryDisplay(w http.ResponseWriter, r *http.Request, beneficiary any, bookings []any) {
func (renderer *Renderer) BeneficiaryDisplay(w http.ResponseWriter, r *http.Request, beneficiary any, bookings []any, beneficiaries_file_types []string, file_types_map map[string]string, documents any) {
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.display.files")
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
state.ViewState = map[string]any{
"beneficiary": beneficiary,
"bookings": bookings,
"beneficiary": beneficiary,
"bookings": bookings,
"beneficiaries_file_types": beneficiaries_file_types,
"file_types_map": file_types_map,
"documents": documents,
}
renderer.Render("beneficiaries_display", w, r, files, state)

View File

@ -1,14 +1,32 @@
package renderer
import "net/http"
import (
"net/http"
fleetsstorage "git.coopgo.io/coopgo-platform/fleets/storage"
)
const vehiclesmanagementMenu = "vehicles_management"
func (renderer *Renderer) VehiclesManagementOverview(w http.ResponseWriter, r *http.Request, vehicles []any) {
func (renderer *Renderer) VehiclesManagementOverview(w http.ResponseWriter, r *http.Request, vehicles []fleetsstorage.Vehicle, vehicles_map map[string]fleetsstorage.Vehicle, bookings []fleetsstorage.Booking) {
files := renderer.ThemeConfig.GetStringSlice("views.vehicles_management.overview.files")
state := NewState(r, renderer.ThemeConfig, vehiclesmanagementMenu)
state.ViewState = map[string]any{
"vehicles": vehicles,
"vehicles": vehicles,
"bookings": bookings,
"vehicles_map": vehicles_map,
}
renderer.Render("fleet overview", w, r, files, state)
}
func (renderer *Renderer) VehiclesManagementBookingsList(w http.ResponseWriter, r *http.Request, vehicles_map map[string]fleetsstorage.Vehicle, bookings []fleetsstorage.Booking, cacheid string) {
files := renderer.ThemeConfig.GetStringSlice("views.vehicles_management.bookings_list.files")
state := NewState(r, renderer.ThemeConfig, vehiclesmanagementMenu)
state.ViewState = map[string]any{
"bookings": bookings,
"vehicles_map": vehicles_map,
"cacheid": cacheid,
}
renderer.Render("fleet overview", w, r, files, state)

View File

@ -51,6 +51,10 @@ views:
- web/layouts/vehicles_management/_partials/bookings-list.html
- web/layouts/vehicles_management/_partials/vehicles-list.html
- web/layouts/vehicles_management/overview.html
bookings_list:
files:
- web/layouts/vehicles_management/_partials/bookings-list.html
- web/layouts/vehicles_management/bookings-list.html
fleet_add:
files:
- web/layouts/_partials/address_autocomplete.html
@ -142,11 +146,14 @@ icons:
hero:outline/cog: <svg xmlns="http://www.w3.org/2000/svg" class="%s" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
hero:outline/document-arrow-down: <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="%s"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m.75 12l3 3m0 0l3-3m-3 3v-6m-1.5-9H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" /></svg>
hero:outline/document-text: <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="%s"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" /></svg>
hero:outline/folder-plus: <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="%s"><path stroke-linecap="round" stroke-linejoin="round" d="M12 10.5v6m3-3H9m4.06-7.19l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" /></svg>
hero:outline/home: <svg xmlns="http://www.w3.org/2000/svg" class="%s" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" /></svg>
hero:outline/map: <svg xmlns="http://www.w3.org/2000/svg" class="%s" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7" /></svg>
hero:outline/office-building: <svg xmlns="http://www.w3.org/2000/svg" class="%s" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" /></svg>
hero:outline/paper-clip: <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="%s"><path stroke-linecap="round" stroke-linejoin="round" d="M18.375 12.739l-7.693 7.693a4.5 4.5 0 01-6.364-6.364l10.94-10.94A3 3 0 1119.5 7.372L8.552 18.32m.009-.01l-.01.01m5.699-9.941l-7.81 7.81a1.5 1.5 0 002.112 2.13" /></svg>
hero:outline/plus-circle: <svg xmlns="http://www.w3.org/2000/svg" class="%s" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
hero:outline/shield-check: <svg xmlns="http://www.w3.org/2000/svg" class="%s" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" /></svg>
hero:outline/table-cells: <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="%s"><path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 01-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0112 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5" /></svg>
hero:outline/user-group: <svg xmlns="http://www.w3.org/2000/svg" class="%s" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" /></svg>
hero:outline/x: <svg class="%s text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
hero:solid/chevron-right: <svg class="%s text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" /></svg>

View File

@ -0,0 +1,31 @@
{{define "documents_list"}}
<div class="-mx-4 mt-10 ring-1 ring-gray-300 sm:-mx-6 md:mx-0 md:rounded-lg">
<table class="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">Type</th>
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">Nom du document</th>
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
<span class="sr-only">Actions</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="relative py-4 pl-4 sm:pl-6 pr-3 text-sm">
<div class="font-medium text-gray-900">
<span class="bg-co-blue text-xs text-white rounded-xl p-1 mr-2">{{index $.ViewState.file_types_map .Metadata.Type}}</span>
</div>
</td>
<td class="px-3 py-3.5 text-sm text-gray-500 lg:table-cell">{{.Metadata.Name}}</td>
<td class="relative py-3.5 pl-3 pr-4 sm:pr-6 text-right text-sm font-medium">
<button type="button" class="inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium leading-4 text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-co-blue focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-30">Télécharger<span class="sr-only"> le fichier</span></button>
</td>
</tr>
<!-- More plans... -->
</tbody>
</table>
</div>
{{end}}

View File

@ -1,5 +1,135 @@
{{define "beneficiary_files"}}
<div class="px-4 py-6 sm:px-6">
TODO Fichiers
<div class="px-4 py-6 sm:px-6"
x-data="{
fields: {
name: null,
type: null,
file: null,
},
rules: {
name: ['required'],
type: ['required'],
file: ['required'],
},
formValidation: {
valid: false,
fields: {
name: {valid: null},
type: {valid: null},
file: {valid: null},
}
},
isFormValid: true,
validate() {
this.formValidation = Iodine.assert(this.fields, this.rules)
},
validateField(field) {
this.formValidation.fields[field] = Iodine.assert(this.fields[field], this.rules[field])
},
submit(event) {
this.validate()
if(!this.formValidation.valid) {
this.isFormValid = false
event.preventDefault()
}
return this.formValidation.valid
}
}">
{{if eq (len .ViewState.documents) 0}}
<p class="p-12 text-gray-500 text-center text-md">Aucun document</p>
{{end}}
{{if gt (len .ViewState.documents) 0}}
<div class="-mx-4 mb-10 ring-1 ring-gray-300 sm:-mx-6 md:mx-0 md:rounded-lg">
<table class="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">Type</th>
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">Nom du document</th>
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">Ajouté le</th>
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
<span class="sr-only">Actions</span>
</th>
</tr>
</thead>
<tbody>
{{range .ViewState.documents}}
<tr>
<td class="relative py-4 pl-4 sm:pl-6 pr-3 text-sm">
<div class="font-medium text-gray-900">
<span class="bg-co-blue text-xs text-white rounded-xl p-1 mr-2">{{index $.ViewState.file_types_map .Metadata.Type}}</span>
</div>
</td>
<td class="px-3 py-3.5 text-sm text-gray-900 lg:table-cell">{{.Metadata.Name}}</td>
<td class="px-3 py-3.5 text-sm text-gray-500 lg:table-cell">{{.LastModified.Format "02/01/2006"}}</td>
<td class="relative py-3.5 pl-3 pr-4 sm:pr-6 text-right text-sm font-medium">
<a href="/app/beneficiaries/{{$.ViewState.beneficiary.ID}}/documents/{{.FileName}}" target="_blank">
<button type="button" class="inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium leading-4 text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-co-blue focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-30">Voir<span class="sr-only"> le document</span></button>
</a>
</td>
</tr>
{{end}}
<!-- More plans... -->
</tbody>
</table>
</div>
{{end}}
<h3 class="text-lg">Ajouter un document</h3>
<form method="POST" action="/app/beneficiaries/e7616eac-4a87-4396-a505-23e0421b9c4c/documents" @submit="submit" enctype="multipart/form-data">
<div class="md:grid md:grid-cols-6 p-2">
<div class="sm:col-span-2">
<label for="type" class="block text-sm font-medium text-gray-700">Type</label>
<select id="type" name="type" class="mt-1 block w-full rounded-l-2xl border-gray-300 py-2 pl-3 pr-10 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm"
x-model="fields.type" @blur="validateField('type')"
:class="formValidation.fields.type.valid == false ? 'border-co-red border-2' : 'border-gray-300'">
<option value="" selected>Sélectionner un type</option>
{{range .ViewState.beneficiaries_file_types}}
<option value="{{.}}">{{index $.ViewState.file_types_map .}}</option>
{{end}}
</select>
</div>
<div class="sm:col-span-4">
<label for="name" class="block text-sm font-medium text-gray-700">Nom</label>
<input type="text" name="name" id="name"
placeholder="Nom du fichier"
class="mt-1 focus:ring-co-blue focus:border-co-blue block w-full shadow-sm sm:text-sm rounded-r-2xl"
x-model="fields.name" @blur="validateField('name')"
:class="formValidation.fields.name.valid == false ? 'border-co-red border-2' : 'border-gray-300'" />
</div>
<div class="sm:col-span-6 mt-4">
<label for="cover-photo" class="block text-sm font-medium text-gray-700">Téléchargement</label>
<div class="mt-1 flex justify-center rounded-md border-2 border-dashed px-6 pt-5 pb-6"
x-on:drop="console.log('toto')"
:class="formValidation.fields.file.valid == false ? 'border-co-red border-2' : 'border-gray-300'">
<div class="space-y-1 text-center">
{{.IconSet.Icon "hero:outline/folder-plus" "mx-auto h-12 w-12 text-gray-400"}}
<div class="flex text-sm text-gray-600">
<label for="file-upload" class="relative cursor-pointer rounded-md bg-white font-medium text-co-blue focus-within:outline-none focus-within:ring-2 focus-within:ring-co-blue focus-within:ring-offset-2 hover:text-co-blue">
<span>Sélectionnez un fichier </span>
<input id="file-upload" name="file-upload" type="file" class="sr-only"
x-model="fields.file" @blur="validateField('file')">
</label>
<!-- <p class="pl-1">ou glissez-déposez</p> -->
</div>
<p class="text-xs text-gray-500">Jusqu'à 10MB</p>
<p class="text-co-blue p-2" x-text="fields.file" x-if="fields.file"></p>
</div>
</div>
</div>
</div>
<button type="submit"
class="rounded-2xl border border-transparent bg-co-blue px-4 py-2 my-4 mt-8 w-full text-sm font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-co-blue focus:ring-offset-2 sm:w-auto">
Ajouter le document
</button>
</form>
</div>
{{end}}

View File

@ -75,7 +75,7 @@
</section>
<section aria-labelledby="functionalities-title" x-data="{
tab: 'vehicles',
tab: 'documents',
to(event) {
this.tab = event.target.value
}
@ -91,9 +91,11 @@
<option value="journeys">Déplacements</option>
<option value="vehicles">Véhicules</option>
<option value="events">Dispositifs</option>
<option value="files">Documents</option>
<option value="documents">Documents</option>
</select>
</div>
<div class="hidden sm:block">
@ -120,10 +122,10 @@
:class="tab == 'events' ? 'border-co-blue text-co-blue' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'">
Dispositifs </a>
<!-- <a href="#" @click="tab = 'files'"
<a href="#" @click="tab = 'documents'"
class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"
:class="tab == 'files' ? 'border-co-blue text-co-blue' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'">
Documents </a> -->
:class="tab == 'documents' ? 'border-co-blue text-co-blue' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'">
Documents </a>
</nav>
</div>
</div>
@ -132,7 +134,7 @@
<div x-show="tab == 'journeys'">{{template "beneficiary_journeys" .}}</div>
<div x-show="tab == 'vehicles'">{{template "beneficiary_vehicles" .}}</div>
<div x-show="tab == 'events'">{{template "beneficiary_events" .}}</div>
<div x-show="tab == 'files'">{{template "beneficiary_files" .}}</div>
<div x-show="tab == 'documents'">{{template "beneficiary_files" .}}</div>
<div x-show="tab == 'notes'">{{template "beneficiary_notes" .}}</div>
</div>
</div>

View File

@ -32,7 +32,7 @@
</div>
<div class="flex-shrink-0 flex items-center px-4">
<img class="h-8 w-auto" src="/public/images/parcoursmob_logo_whitered.svg" alt="PARCOURSMOB">
<img class="h-8 w-auto" src="/public/images/main_logo.svg" alt="PARCOURSMOB">
</div>
<div class="mt-5 flex-1 h-0 overflow-y-auto">

View File

@ -7,22 +7,19 @@
<table class="min-w-full divide-y divide-gray-300">
<thead class="bg-gray-50">
<tr>
<!-- <th scope="col"
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">
<th scope="col"
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6 text-center">
Statut
</th> -->
</th>
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:pl-6">
Type
</th>
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:pl-6">
Immatriculation
Numéro (Immat / Bicycode)
</th>
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:pl-6">
Beneficiaire
</th>
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:pl-6">
Gestionnaire
</th>
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:pl-6">
Dates
</th>
@ -32,29 +29,35 @@
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
{{range .ViewState.vehicles}}
{{$vehicle := .}}
{{range .Bookings}}
{{range .ViewState.bookings}}
<tr>
<!-- <td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6">
<div class="text-gray-900" >aa</div>
</td> -->
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6">
<div class="text-gray-900" >Voiture</div>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6 text-center">
{{if eq .Status 1 }}
<span class="p-1 bg-co-blue text-white text-xs font-bold rounded-xl" >
A venir
</span>
{{end}}
{{if eq .Status 0 }}
<span class="p-1 bg-co-green text-white text-xs font-bold rounded-xl" >
En cours
</span>
{{end}}
{{if eq .Status -1 }}
<span class="p-1 bg-co-red text-white text-xs font-bold rounded-xl" >
Terminé
</span>
{{end}}
</td>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6">
<div class="text-gray-900" >{{$vehicle.Data.licence_plate}}</div>
<div class="text-gray-900" >{{ (index $.ViewState.vehicles_map .Vehicleid).Type }}</div>
</td>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6">
<div class="text-gray-900" >{{ (index $.ViewState.vehicles_map .Vehicleid).Data.licence_plate }}</div>
</td>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6">
<div class="text-gray-900" ><img class="h-6 w-6 rounded-co"
src="/app/beneficiaries/{{.Driver}}/picture" alt=""></div>
</td>
<!-- <td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6">
<div class="text-gray-900" >aa</div>
</td> -->
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6">
<div class="text-gray-900" >COOPGO</div>
</td>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6">
<div class="text-gray-900" >Du {{(timeFrom .Startdate).Format "02/01/2006"}} au {{(timeFrom .Enddate).Format "02/01/2006"}}</div>
</td>
@ -64,7 +67,6 @@
</td>
</tr>
{{end}}
{{end}}
</tbody>
</table>
</div>

View File

@ -0,0 +1,25 @@
{{define "content"}}
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
<h1 class="text-2xl font-semibold text-gray-900">Historique des réservations de véhicules</h1>
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
</div>
<div class="mt-4 sm:mt-0 sm:ml-16 sm:flex-none">
<a href="/api/cache/{{.ViewState.cacheid}}/export">
<button type="button"
class="inline-flex items-center justify-center bg-white hover:bg-gray-50 border-gray-300 border px-4 py-2 text-gray-700 flex items-center text-sm rounded-2xl focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-co-blue">
{{$.IconSet.Icon "hero:outline/document-arrow-down" "h-5 w-5 mr-3"}}
Exporter
</button>
</a>
</div>
</div>
</div>
{{template "bookings_list" .}}
{{end}}

View File

@ -2,17 +2,31 @@
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
<h1 class="text-2xl font-semibold text-gray-900">Gestion des véhicules et réservations</h1>
<h2 class="text-xl font-semibold text-gray-600 pt-8">Réservations</h2>
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
<h2 class="text-xl font-semibold text-gray-600 pt-8">Réservations en cours et à venir</h2>
</div>
<div class="mt-4 sm:mt-0 sm:ml-16 sm:flex-none">
<a href="/app/vehicles-management/bookings/">
<button type="button"
class="inline-flex items-center justify-center rounded-2xl border border-transparent bg-co-blue px-4 py-2 text-sm font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-co-blue focus:ring-offset-2 sm:w-auto">
{{$.IconSet.Icon "hero:outline/table-cells" "h-5 w-5 mr-3"}}
Historique
</button>
</a>
</div>
</div>
</div>
{{template "bookings_list" .}}
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
<h2 class="text-xl font-semibold text-gray-600 pt-8">Véhicules</h2>
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8 mt-8">
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
<p class="mt-2 text-sm text-gray-700"></p>
<h2 class="text-xl font-semibold text-gray-600 pt-8">Véhicules</h2>
</div>
<div class="mt-4 sm:mt-0 sm:ml-16 sm:flex-none">
<a href="/app/vehicles-management/fleet/add">

View File

@ -806,6 +806,18 @@ html {
left: 1rem;
}
.left-6 {
left: 1.5rem;
}
.-top-px {
top: -1px;
}
.right-6 {
right: 1.5rem;
}
.z-40 {
z-index: 40;
}
@ -993,6 +1005,10 @@ html {
margin-right: -0.25rem;
}
.mb-10 {
margin-bottom: 2.5rem;
}
.block {
display: block;
}
@ -1069,6 +1085,10 @@ html {
height: 0.75rem;
}
.h-px {
height: 1px;
}
.max-h-60 {
max-height: 15rem;
}
@ -1539,6 +1559,10 @@ html {
border-top-width: 2px;
}
.border-dashed {
border-style: dashed;
}
.border-gray-200 {
--tw-border-opacity: 1;
border-color: rgb(229 231 235 / var(--tw-border-opacity));
@ -1665,6 +1689,10 @@ html {
padding: 0.375rem;
}
.p-8 {
padding: 2rem;
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
@ -1820,6 +1848,10 @@ html {
padding-left: 0.375rem;
}
.pb-6 {
padding-bottom: 1.5rem;
}
.text-left {
text-align: left;
}
@ -2075,6 +2107,11 @@ html {
--tw-ring-color: rgb(255 255 255 / var(--tw-ring-opacity));
}
.ring-gray-300 {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity));
}
.ring-opacity-5 {
--tw-ring-opacity: 0.05;
}
@ -2161,6 +2198,11 @@ html {
color: rgb(75 85 99 / var(--tw-text-opacity));
}
.focus-within\:outline-none:focus-within {
outline: 2px solid transparent;
outline-offset: 2px;
}
.focus-within\:ring-2:focus-within {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@ -2172,6 +2214,11 @@ html {
--tw-ring-color: rgb(36 56 135 / var(--tw-ring-opacity));
}
.focus-within\:ring-indigo-500:focus-within {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
}
.focus-within\:ring-offset-2:focus-within {
--tw-ring-offset-width: 2px;
}
@ -2249,6 +2296,11 @@ html {
color: inherit;
}
.hover\:text-indigo-500:hover {
--tw-text-opacity: 1;
color: rgb(99 102 241 / var(--tw-text-opacity));
}
.focus\:border-transparent:focus {
border-color: transparent;
}
@ -2343,6 +2395,14 @@ html {
--tw-ring-offset-color: #f3f4f6;
}
.disabled\:cursor-not-allowed:disabled {
cursor: not-allowed;
}
.disabled\:opacity-30:disabled {
opacity: 0.3;
}
.group:hover .group-hover\:text-gray-500 {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
@ -2395,6 +2455,10 @@ html {
display: block;
}
.sm\:inline {
display: inline;
}
.sm\:flex {
display: flex;
}
@ -2569,6 +2633,19 @@ html {
grid-column: span 2 / span 2;
}
.md\:col-span-3 {
grid-column: span 3 / span 3;
}
.md\:col-span-6 {
grid-column: span 6 / span 6;
}
.md\:mx-0 {
margin-left: 0px;
margin-right: 0px;
}
.md\:ml-0 {
margin-left: 0px;
}
@ -2702,6 +2779,14 @@ html {
margin-right: -2rem;
}
.lg\:table-cell {
display: table-cell;
}
.lg\:hidden {
display: none;
}
.lg\:max-w-7xl {
max-width: 80rem;
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 374.2 33.2"><defs><style>.cls-1{fill:#ff1300;}.cls-2{fill:#fff;}</style></defs><g id="Calque_2" data-name="Calque 2"><g id="Calque_1-2" data-name="Calque 1"><path class="cls-1" d="M300.9.6a4.7,4.7,0,0,1,4.9,4.9V32.6h-8.6a4.7,4.7,0,0,1-4.9-4.9V14.1h-.9c-.6,0-1,.6-1,1.5v17H282a4.7,4.7,0,0,1-4.9-4.9V14.1h-1a1.4,1.4,0,0,0-.9,1.5v17H263a1.2,1.2,0,0,1-1.2-1.2V5.5A4.7,4.7,0,0,1,266.7.6h17.9l-.7,5a.9.9,0,0,0,.7,1.1.9.9,0,0,0,1-.8l.8-4.6a.9.9,0,0,1,.9-.7Z"/><path class="cls-1" d="M341.1,16.4c0,9.1-1.9,16.8-16.5,16.8S307.8,25,307.8,16.4,310.6,0,324.6,0,341.1,7.8,341.1,16.4Z"/><path class="cls-1" d="M344.3,32.6a1.2,1.2,0,0,1-1.2-1.2V1.8A1.2,1.2,0,0,1,344.3.6h18.8c6.9,0,10.4,2.9,10.4,8.1s-1.6,6.9-4.5,7.5h0c2.9.6,5.2,3.2,5.2,7.7s-3.5,8.6-10.4,8.6Z"/><path class="cls-2" d="M16.2,11.6c0-.6-.4-.9-1-.9h-.8V31.4a1.2,1.2,0,0,1-1.2,1.2H1.2A1.2,1.2,0,0,1,0,31.4V1.8A1.2,1.2,0,0,1,1.2.6H16.8C25.7.6,30.9,4.2,31,10.7s-4.1,9.9-9.4,10H16.1Z"/><path class="cls-2" d="M44.9,23.1H43.2L40,31.9a1.1,1.1,0,0,1-1.2.7H26.9a1.3,1.3,0,0,1-1.3-1.9L37,3.4A4.5,4.5,0,0,1,41.3.6h5.8a4.1,4.1,0,0,1,4,2.6L62.6,30.8c.5,1-.2,1.8-1.3,1.8H41.7Z"/><path class="cls-2" d="M66.1,32.6a1.2,1.2,0,0,1-1.2-1.2V1.8A1.2,1.2,0,0,1,66.1.6H83.2C92.7.6,95.5,7,95.6,12.3c0,3.3-.8,6.9-3.4,8.3l3.4,12H84.4c-2.3,0-5.2-.7-5.9-2.7L71.9,10.7a1,1,0,0,0-1.2-.7,1,1,0,0,0-.5,1.3l7.2,21.3Z"/><path class="cls-2" d="M129.6,17.1c.8,0,1.3.5,1.2,1.2-.2,8.3-2.9,14.9-16.4,14.9-15.8.1-16.8-8.2-16.8-16.8S100.5,0,114.4,0c15.7,0,16.5,8,16.5,15.4H115.3V11.3c0-.8-.4-1.2-1-1.2s-.9.4-.9,1.2V21.9c0,.9.4,1.2.9,1.2s1-.3,1-1.2V17.1Z"/><path class="cls-2" d="M166.2,16.4c0,9.1-2,16.8-16.6,16.8S132.8,25,132.8,16.4,135.7,0,149.6,0,166.2,7.8,166.2,16.4Z"/><path class="cls-2" d="M200.5,1.8V12.2c0,12.7-1.4,21-16.3,21s-16-8.4-16-20.9V1.8A1.2,1.2,0,0,1,169.4.6h13a.9.9,0,0,1,.9.9V21.8c0,.9.4,1.2,1,1.2s.9-.3.9-1.2V1.5a.9.9,0,0,1,.9-.9h13.1A1.2,1.2,0,0,1,200.5,1.8Z"/><path class="cls-2" d="M203.9,32.6a1.2,1.2,0,0,1-1.3-1.2V1.8A1.2,1.2,0,0,1,203.8.6h17.1c9.5,0,12.3,6.4,12.4,11.7,0,3.3-.8,6.9-3.4,8.3l3.4,12H222.1c-2.3,0-5.2-.7-5.9-2.7l-6.6-19.2a1,1,0,0,0-1.2-.7,1,1,0,0,0-.5,1.3l7.2,21.3Z"/><path class="cls-2" d="M235.8,29.2v-10a1,1,0,0,1,1.5-1l11.1,5.1a1,1,0,0,0,1.2-.4.9.9,0,0,0-.6-1.2l-9.3-4.4c-4.5-2.2-4.4-5.5-4.4-8.2,0-7.6,7.4-9.1,14.6-9.1,5.4,0,12.1,1.8,14.3,4.4v9.2a1,1,0,0,1-1.5,1L252.3,9.8a1,1,0,0,0-1.3.4q-.3.8.6,1.2l8.5,4.1c5.3,2.6,4.7,4.9,4.7,9.2s-6.3,8.5-14.9,8.5C244.7,33.2,238,31.6,235.8,29.2Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

23
utils/sorting/fleets.go Normal file
View File

@ -0,0 +1,23 @@
package sorting
import (
"strings"
fleetsstorage "git.coopgo.io/coopgo-platform/fleets/storage"
)
type VehiclesByLicencePlate []fleetsstorage.Vehicle
func (a VehiclesByLicencePlate) Len() int { return len(a) }
func (a VehiclesByLicencePlate) Less(i, j int) bool {
return strings.Compare(a[i].Data["licence_plate"].(string), a[j].Data["licence_plate"].(string)) < 0
}
func (a VehiclesByLicencePlate) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
type BookingsByStartdate []fleetsstorage.Booking
func (a BookingsByStartdate) Len() int { return len(a) }
func (a BookingsByStartdate) Less(i, j int) bool {
return a[i].Startdate.Before(a[j].Startdate)
}
func (a BookingsByStartdate) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

1
utils/sorting/sorting.go Normal file
View File

@ -0,0 +1 @@
package sorting

30
utils/storage/files.go Normal file
View File

@ -0,0 +1,30 @@
package storage
import (
"io"
"time"
"github.com/spf13/viper"
)
const (
PREFIX_BENEFICIARIES = "beneficiaries"
)
type FileInfo struct {
Key string
FileName string
LastModified time.Time
ContentType string
Metadata map[string]string
}
type FileStorage interface {
Put(reader io.Reader, prefix string, filename string, size int64, metadata map[string]string) error
List(prefix string) []FileInfo
Get(prefix string, file string) (io.Reader, *FileInfo, error)
}
func NewFileStorage(cfg *viper.Viper) (FileStorage, error) {
return NewMinioStorageHandler(cfg)
}

104
utils/storage/minio.go Normal file
View File

@ -0,0 +1,104 @@
package storage
import (
"context"
"fmt"
"io"
"strings"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/spf13/viper"
)
type MinioStorageHandler struct {
*minio.Client
BucketName string
}
func NewMinioStorageHandler(cfg *viper.Viper) (*MinioStorageHandler, error) {
minioClient, err := minio.New(cfg.GetString("storage.files.minio.endpoint"), &minio.Options{
Creds: credentials.NewStaticV4(cfg.GetString("storage.files.minio.access_key"), cfg.GetString("storage.files.minio.secret_key"), ""),
Secure: cfg.GetBool("storage.files.minio.use_ssl"),
})
if err != nil {
fmt.Println(err)
return nil, err
}
return &MinioStorageHandler{
Client: minioClient,
BucketName: cfg.GetString("storage.files.minio.bucket_name"),
}, nil
}
func (s *MinioStorageHandler) Put(reader io.Reader, prefix string, filename string, size int64, metadata map[string]string) error {
s.Client.PutObject(context.TODO(), s.BucketName, prefix+"/"+filename, reader, size, minio.PutObjectOptions{
UserMetadata: metadata,
})
return nil
}
func (s *MinioStorageHandler) List(prefix string) []FileInfo {
res := []FileInfo{}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
objectCh := s.Client.ListObjects(ctx, s.BucketName, minio.ListObjectsOptions{
Prefix: prefix,
Recursive: true,
})
for object := range objectCh {
if object.Err != nil {
fmt.Println("Error : ", object.Err)
continue
}
objinfo, err := s.Client.StatObject(context.Background(), s.BucketName, object.Key, minio.StatObjectOptions{})
if err != nil {
fmt.Println(err)
continue
}
path := strings.Split(object.Key, "/")
fileinfo := FileInfo{
Key: object.Key,
FileName: path[len(path)-1],
LastModified: object.LastModified,
ContentType: object.ContentType,
Metadata: objinfo.UserMetadata,
}
res = append(res, fileinfo)
}
return res
}
func (s *MinioStorageHandler) Get(prefix string, file string) (io.Reader, *FileInfo, error) {
object, err := s.Client.GetObject(context.Background(), s.BucketName, prefix+"/"+file, minio.GetObjectOptions{})
if err != nil {
fmt.Println(err)
return nil, nil, err
}
objinfo, err := s.Client.StatObject(context.Background(), s.BucketName, prefix+"/"+file, minio.StatObjectOptions{})
if err != nil {
fmt.Println(err)
return nil, nil, err
}
path := strings.Split(objinfo.Key, "/")
fileinfo := &FileInfo{
Key: objinfo.Key,
FileName: path[len(path)-1],
LastModified: objinfo.LastModified,
ContentType: objinfo.ContentType,
Metadata: objinfo.UserMetadata,
}
return object, fileinfo, nil
}

View File

@ -34,7 +34,7 @@ func NewSessionStore(client KVHandler, keyPairs ...[]byte) *SessionStore {
Path: "/",
MaxAge: sessionExpire,
},
DefaultMaxAge: 60 * 20, // 20 minutes seems like a reasonable default
DefaultMaxAge: sessionExpire, // 20 minutes seems like a reasonable default
//maxLength: 4096,
keyPrefix: "session/",
}