diff --git a/go.mod b/go.mod index 35027da..dd80b97 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 68c1ff4..dd98fc9 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/handlers/api/oidc.go b/handlers/api/oidc.go index b517129..eead6ea 100644 --- a/handlers/api/oidc.go +++ b/handlers/api/oidc.go @@ -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) } diff --git a/handlers/application/application.go b/handlers/application/application.go index 64c402c..a518d51 100644 --- a/handlers/application/application.go +++ b/handlers/application/application.go @@ -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 } diff --git a/handlers/application/beneficiaries.go b/handlers/application/beneficiaries.go index eb77f14..6e34a3a 100644 --- a/handlers/application/beneficiaries.go +++ b/handlers/application/beneficiaries.go @@ -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"] diff --git a/handlers/application/vehicles-management.go b/handlers/application/vehicles-management.go index cc504ad..761b127 100644 --- a/handlers/application/vehicles-management.go +++ b/handlers/application/vehicles-management.go @@ -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) { diff --git a/main.go b/main.go index 56cffec..285e393 100644 --- a/main.go +++ b/main.go @@ -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) diff --git a/renderer/beneficiaries.go b/renderer/beneficiaries.go index a28ec8e..1d5b6aa 100644 --- a/renderer/beneficiaries.go +++ b/renderer/beneficiaries.go @@ -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) diff --git a/renderer/vehicle-management.go b/renderer/vehicle-management.go index dbb9217..7b7533f 100644 --- a/renderer/vehicle-management.go +++ b/renderer/vehicle-management.go @@ -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) diff --git a/themes/default/config.yaml b/themes/default/config.yaml index 49aa1f9..aff77ec 100644 --- a/themes/default/config.yaml +++ b/themes/default/config.yaml @@ -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: hero:outline/document-arrow-down: hero:outline/document-text: + hero:outline/folder-plus: hero:outline/home: hero:outline/map: hero:outline/office-building: + hero:outline/paper-clip: hero:outline/plus-circle: hero:outline/shield-check: + hero:outline/table-cells: hero:outline/user-group: hero:outline/x: hero:solid/chevron-right: diff --git a/themes/default/web/layouts/_partials/files_list.html b/themes/default/web/layouts/_partials/files_list.html new file mode 100644 index 0000000..0f10791 --- /dev/null +++ b/themes/default/web/layouts/_partials/files_list.html @@ -0,0 +1,31 @@ +{{define "documents_list"}} +
+ + + + + + + + + + + + + + + + + + +
Type + Actions +
+
+ {{index $.ViewState.file_types_map .Metadata.Type}} +
+
{{.Metadata.Name}} + +
+
+{{end}} \ No newline at end of file diff --git a/themes/default/web/layouts/beneficiaries/_partials/beneficiary-files.html b/themes/default/web/layouts/beneficiaries/_partials/beneficiary-files.html index ffd6c5a..b4a3de4 100644 --- a/themes/default/web/layouts/beneficiaries/_partials/beneficiary-files.html +++ b/themes/default/web/layouts/beneficiaries/_partials/beneficiary-files.html @@ -1,5 +1,135 @@ {{define "beneficiary_files"}} -
- TODO Fichiers +
+ {{if eq (len .ViewState.documents) 0}} +

Aucun document

+ {{end}} + + + {{if gt (len .ViewState.documents) 0}} + +
+ + + + + + + + + + + {{range .ViewState.documents}} + + + + + + + {{end}} + + + + +
Type + Actions +
+
+ {{index $.ViewState.file_types_map .Metadata.Type}} +
+
{{.Metadata.Name}}{{.LastModified.Format "02/01/2006"}} + + + +
+
+ + {{end}} + +

Ajouter un document

+
+
+
+ + +
+
+ + +
+
+ +
+
+ {{.IconSet.Icon "hero:outline/folder-plus" "mx-auto h-12 w-12 text-gray-400"}} +
+ + + + +
+

Jusqu'à 10MB

+

+
+
+
+
+ +
+
{{end}} \ No newline at end of file diff --git a/themes/default/web/layouts/beneficiaries/display.html b/themes/default/web/layouts/beneficiaries/display.html index 4db8599..6829e5a 100644 --- a/themes/default/web/layouts/beneficiaries/display.html +++ b/themes/default/web/layouts/beneficiaries/display.html @@ -75,7 +75,7 @@
Déplacements + + - +
@@ -132,7 +134,7 @@
{{template "beneficiary_journeys" .}}
{{template "beneficiary_vehicles" .}}
{{template "beneficiary_events" .}}
-
{{template "beneficiary_files" .}}
+
{{template "beneficiary_files" .}}
{{template "beneficiary_notes" .}}
diff --git a/themes/default/web/layouts/layout.html b/themes/default/web/layouts/layout.html index 2e27174..980f5c5 100644 --- a/themes/default/web/layouts/layout.html +++ b/themes/default/web/layouts/layout.html @@ -32,7 +32,7 @@
- PARCOURSMOB + PARCOURSMOB
diff --git a/themes/default/web/layouts/vehicles_management/bookings-list.html b/themes/default/web/layouts/vehicles_management/bookings-list.html new file mode 100644 index 0000000..6bd90c0 --- /dev/null +++ b/themes/default/web/layouts/vehicles_management/bookings-list.html @@ -0,0 +1,25 @@ +{{define "content"}} +
+

Historique des réservations de véhicules

+ + +
+
+ +
+ +
+
+ +{{template "bookings_list" .}} + +{{end}} \ No newline at end of file diff --git a/themes/default/web/layouts/vehicles_management/overview.html b/themes/default/web/layouts/vehicles_management/overview.html index 9ab5eda..60fd3ab 100644 --- a/themes/default/web/layouts/vehicles_management/overview.html +++ b/themes/default/web/layouts/vehicles_management/overview.html @@ -2,17 +2,31 @@

Gestion des véhicules et réservations

-

Réservations

+ +
+
+

Réservations en cours et à venir

+
+ +
{{template "bookings_list" .}} -
-

Véhicules

+
+
-

+

Véhicules

diff --git a/themes/default/web/public/css/main.css b/themes/default/web/public/css/main.css index ee473ab..bb8ed84 100644 --- a/themes/default/web/public/css/main.css +++ b/themes/default/web/public/css/main.css @@ -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; } diff --git a/themes/default/web/public/images/main_logo.svg b/themes/default/web/public/images/main_logo.svg new file mode 100644 index 0000000..d267bdd --- /dev/null +++ b/themes/default/web/public/images/main_logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/utils/sorting/fleets.go b/utils/sorting/fleets.go new file mode 100644 index 0000000..c973585 --- /dev/null +++ b/utils/sorting/fleets.go @@ -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] } diff --git a/utils/sorting/sorting.go b/utils/sorting/sorting.go new file mode 100644 index 0000000..6841ee1 --- /dev/null +++ b/utils/sorting/sorting.go @@ -0,0 +1 @@ +package sorting diff --git a/utils/storage/files.go b/utils/storage/files.go new file mode 100644 index 0000000..056bafb --- /dev/null +++ b/utils/storage/files.go @@ -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) +} diff --git a/utils/storage/minio.go b/utils/storage/minio.go new file mode 100644 index 0000000..5cfbe03 --- /dev/null +++ b/utils/storage/minio.go @@ -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 +} diff --git a/utils/storage/sessions.go b/utils/storage/sessions.go index 05cf5e6..d52a57f 100644 --- a/utils/storage/sessions.go +++ b/utils/storage/sessions.go @@ -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/", }