first commit

This commit is contained in:
sbouaram 2023-10-20 13:41:39 +02:00
commit 6696cd3152
65 changed files with 11374 additions and 0 deletions

16
config.go Normal file
View File

@ -0,0 +1,16 @@
package main
import (
"github.com/spf13/viper"
"strings"
)
func ReadConfig() (*viper.Viper, error) {
v := viper.New()
v.SetConfigName("config")
v.AddConfigPath(".")
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
v.AutomaticEnv()
err := v.ReadInConfig()
return v, err
}

36
config.yaml Normal file
View File

@ -0,0 +1,36 @@
name: COOPGO Solidarity Service
dev_env: true
storage:
db:
type: psql
psql:
host: localhost
dbname: coopgo_platform
user: postgres
password: postgres
sslmode: disable
port: 5432
schema: solidarity_service
tables:
drivers: drivers
passengers: passengers
bookings: bookings
services:
grpc:
enable: true
port: 8089
solidarity-api:
enable: true
address: 0.0.0.0:9999
routing:
type: valhalla
valhalla:
base_url: https://valhalla.coopgo.io/

44
go.mod Normal file
View File

@ -0,0 +1,44 @@
module solidarity-service
go 1.20
require (
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20230403183358-4d30329f06be
github.com/golang/protobuf v1.5.3
github.com/google/uuid v1.3.1
github.com/lib/pq v1.10.9
github.com/paulmach/orb v0.10.0
github.com/rs/zerolog v1.31.0
github.com/spf13/viper v1.17.0
google.golang.org/grpc v1.58.3
google.golang.org/protobuf v1.31.0
)
require (
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.10.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twpayne/go-polyline v1.1.1 // indirect
go.mongodb.org/mongo-driver v1.11.4 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.15.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

552
go.sum Normal file
View File

@ -0,0 +1,552 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20230403183358-4d30329f06be h1:VIzWX8NftKzQX1clunLaMf79Ut1dygcCc/ZLV/iWOaY=
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20230403183358-4d30329f06be/go.mod h1:Nh7o15LlV0OuO9zxvJIs9FlelpeAaLYkXtFdgIkFrgg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
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=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
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/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s=
github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/twpayne/go-polyline v1.1.1 h1:/tSF1BR7rN4HWj4XKqvRUNrCiYVMCvywxTFVofvDV0w=
github.com/twpayne/go-polyline v1.1.1/go.mod h1:ybd9IWWivW/rlXPXuuckeKUyF3yrIim+iqA7kSl4NFY=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizXas=
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ=
google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

21
handler/handler.go Normal file
View File

@ -0,0 +1,21 @@
package handler
import (
"git.coopgo.io/coopgo-platform/routing-service"
"github.com/spf13/viper"
"solidarity-service/storage"
)
type SolidarityServiceHandler struct {
Config *viper.Viper
Routing routing.RoutingService
Storage storage.Storage
}
func NewSolidarityServiceHandler(cfg *viper.Viper, routing routing.RoutingService, storage storage.Storage) (*SolidarityServiceHandler, error) {
return &SolidarityServiceHandler{
Config: cfg,
Routing: routing,
Storage: storage,
}, nil
}

View File

@ -0,0 +1,14 @@
package handler
import (
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"
"solidarity-service/servers/utils"
)
func (handler *SolidarityServiceHandler) CalculateDistanceBetweenFeatures(feature1, feature2 *geojson.Feature) int64 {
coords1 := feature1.Geometry.(orb.Point)
coords2 := feature2.Geometry.(orb.Point)
distance := utils.Haversine(coords1[1], coords1[0], coords2[1], coords2[0])
return int64(distance)
}

23
handler/routing.go Normal file
View File

@ -0,0 +1,23 @@
package handler
import (
"github.com/paulmach/orb"
"time"
)
type RoutingService interface {
Route(locations []orb.Point) (route *Route, err error)
}
type Route struct {
Summary RouteSummary
Legs []RouteLeg
}
type RouteSummary struct {
Polyline string
}
type RouteLeg struct {
Distance float64
Duration time.Duration
Polyline string
}

98
handler/services.go Normal file
View File

@ -0,0 +1,98 @@
package handler
import (
"context"
"github.com/paulmach/orb/geojson"
"solidarity-service/internal"
)
func (s *SolidarityServiceHandler) GetPassenger(ctx context.Context, id string) (passenger internal.Passenger, err error) {
passenger, err = s.Storage.GetPassenger(id)
if err != nil {
return internal.Passenger{}, err
}
return passenger, nil
}
func (s *SolidarityServiceHandler) GetDriver(ctx context.Context, id string) (driver internal.Driver, err error) {
driver, err = s.Storage.GetDriver(id)
if err != nil {
return internal.Driver{}, err
}
return driver, nil
}
func (s *SolidarityServiceHandler) SetDriverAvailabilities(ctx context.Context, driver internal.Driver) (err error) {
driver.Driver.Operator = "internal-grpc"
err = s.Storage.CreateDriver(driver)
if err != nil {
return err
}
return nil
}
func (s *SolidarityServiceHandler) SetPassengerTrip(ctx context.Context, passenger internal.Passenger) (err error) {
passenger.Passenger.Operator = "internal-grpc"
err = s.Storage.CreatePassenger(passenger)
if err != nil {
return err
}
return nil
}
func (s *SolidarityServiceHandler) CreateBooking(ctx context.Context, bookingRequest internal.BookingRequest) (passenger internal.Passenger, driver internal.Driver, err error) {
bookingRequest.Operator = "internal-grpc"
err = s.Storage.CreateBooking(bookingRequest)
if err != nil {
return internal.Passenger{}, internal.Driver{}, err
}
passenger, err = s.Storage.GetPassenger(bookingRequest.Passenger_id)
if err != nil {
return internal.Passenger{}, internal.Driver{}, err
}
driver, err = s.Storage.GetDriver(bookingRequest.Driver_id)
if err != nil {
return internal.Passenger{}, internal.Driver{}, err
}
return passenger, driver, nil
}
func (s *SolidarityServiceHandler) UpdateBooking(ctx context.Context, bookingId string, status internal.BookingStatus) (err error) {
err = s.Storage.UpdateBookingStatus(bookingId, status)
if err != nil {
return err
}
return nil
}
func (s *SolidarityServiceHandler) GetBooking(ctx context.Context, bookingId string) (booking internal.Booking, passenger internal.Passenger, driver internal.Driver, err error) {
booking, err = s.Storage.GetBooking(bookingId)
if err != nil {
return internal.Booking{}, internal.Passenger{}, internal.Driver{}, err
}
passenger, err = s.Storage.GetPassenger(booking.Passenger.ID)
if err != nil {
return internal.Booking{}, internal.Passenger{}, internal.Driver{}, err
}
driver, err = s.Storage.GetDriver(booking.Driver.ID)
if err != nil {
return internal.Booking{}, internal.Passenger{}, internal.Driver{}, err
}
return booking, passenger, driver, nil
}
func (s *SolidarityServiceHandler) GetBookingsByStatus(ctx context.Context, status string, filterType string, id string) (bookings []internal.Booking, err error) {
bookings, err = s.Storage.FilterUserBookingsByStatus(filterType, internal.BookingStatus(status), id)
if err != nil {
return nil, err
}
return bookings, nil
}
func (s *SolidarityServiceHandler) GetDriverJourneys(ctx context.Context, departure_route *geojson.Feature, departure_date int64) (drivers []internal.Driver, err error) {
drivers, err = s.Storage.DriverJourneys(departure_route, departure_date)
if err != nil {
return nil, err
}
return drivers, nil
}

52
handler/trip_duration.go Normal file
View File

@ -0,0 +1,52 @@
package handler
import (
"encoding/json"
"errors"
"fmt"
"github.com/paulmach/orb/geojson"
"net/http"
)
func (handler *SolidarityServiceHandler) CalculateDurationBetweenFeatures(feature1, feature2 *geojson.Feature) (int64, error) {
coords1 := feature1.Point()
coords2 := feature2.Point()
routing_base_url := handler.Config.GetString("routing.valhalla.base_url")
url := fmt.Sprintf("%sroute?json=%s", routing_base_url, createJSONROUTERequest(coords1.X(), coords1.Y(), coords2.X(), coords2.Y()))
response, err := http.Get(url)
if err != nil {
return 0, errors.New("routing service error")
}
var result map[string]interface{}
decoder := json.NewDecoder(response.Body)
if err := decoder.Decode(&result); err != nil {
return 0, errors.New("routing response decoding error")
}
trip, ok := result["trip"].(map[string]interface{})
if !ok {
return 0, errors.New("routing response decoding error")
}
summary, ok := trip["summary"].(map[string]interface{})
if !ok {
return 0, errors.New("routing response decoding error")
}
duration, ok := summary["time"].(float64)
if !ok {
return 0, errors.New("routing response decoding error")
}
return int64(duration), nil
}
func createJSONROUTERequest(lat1, lon1, lat2, lon2 float64) string {
request := map[string]interface{}{
"locations": []map[string]float64{
{"lat": lat1, "lon": lon1},
{"lat": lat2, "lon": lon2},
},
"costing": "auto",
}
jsonRequest, _ := json.Marshal(request)
return string(jsonRequest)
}

95
internal/models.go Normal file
View File

@ -0,0 +1,95 @@
package internal
import (
"github.com/paulmach/orb/geojson"
)
const (
Punctual AvailabilitiesType = "PUNCTUAL"
Regular AvailabilitiesType = "REGULAR"
BookingStatusINITIATED BookingStatus = "INITIATED"
BookingStatusWAITINGPASSENGERCONFIRMATION BookingStatus = "WAITING_PASSENGER_CONFIRMATION"
BookingStatusWAITINGDRIVERCONFIRMATION BookingStatus = "WAITING_DRIVER_CONFIRMATION"
BookingStatusCONFIRMED BookingStatus = "CONFIRMED"
BookingStatusCANCELLED BookingStatus = "CANCELLED"
BookingStatusCOMPLETEDPENDINGVALIDATION BookingStatus = "COMPLETED_PENDING_VALIDATION"
BookingStatusVALIDATED BookingStatus = "VALIDATED"
)
type Passenger struct {
Passenger_departure_address *geojson.Feature
Passenger_destination_address *geojson.Feature
Passenger_pickup_date int64
Passenger User
Preferences Preferences
}
type Driver struct {
Driver_departure_address *geojson.Feature
Radius int32
Driver User
Preferences Preferences
AvailabilitiesType AvailabilitiesType
RegularAvailabilities []RegularAvailabilities `json:"availabilities,omitempty"`
PunctualAvailabilities []PunctualAvailabilities `json:"availabilities,omitempty"`
Car Car `json:"car,omitempty"`
}
type Car struct {
Model string `json:"model,omitempty"`
Brand string `json:"brand,omitempty"`
}
type AvailabilitiesType string
type BookingStatus string
type User struct {
ID string `json:"id"`
Operator string `json:"operator"`
Alias string `json:"alias"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
Grade int64 `json:"grade,omitempty"`
Picture string `json:"picture,omitempty"`
Gender string `json:"gender,omitempty"`
VerifiedIdentity bool `json:"verified_identity,omitempty"`
}
type Preferences struct {
Smoking bool `json:"smoking,omitempty"`
Animals bool `json:"animals,omitempty"`
Music bool `json:"music,omitempty"`
Is_talker bool `json:"is_talker,omitempty"`
Luggage_size int64 `json:"luggage_size,omitempty"`
}
type BookingRequest struct {
ID string `json:"id"`
Passenger_id string `json:"passenger_id"`
Driver_id string `json:"driver_id"`
Status BookingStatus `json:"booking_status"`
Details map[string]any `json:"booking_details"`
Operator string `json:"operator"`
}
type Booking struct {
ID string `json:"id"`
Passenger User `json:"passenger"`
Driver User `json:"driver"`
PassengerPickupAddress *geojson.Feature
PassengerDropAddress *geojson.Feature
Status BookingStatus `json:"booking_status"`
Details map[string]any `json:"booking_details"`
}
type RegularAvailabilities struct {
DayOfWeek string `json:"dayOfWeek"`
StartTime string `json:"startTime"`
EndTime string `json:"endTime"`
}
type PunctualAvailabilities struct {
Date int64 `json:"date"`
StartTime string `json:"startTime"`
EndTime string `json:"endTime"`
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@ -0,0 +1,40 @@
.openapi-generator-ignore
Dockerfile
README.md
api/openapi.yaml
go.mod
go/api.go
go/api_bookings_filter.go
go/api_bookings_filter_service.go
go/api_driver_availability_and_schedule.go
go/api_driver_availability_and_schedule_service.go
go/api_interact.go
go/api_interact_service.go
go/api_passenger_trip_request.go
go/api_passenger_trip_request_service.go
go/api_search.go
go/api_search_service.go
go/error.go
go/helpers.go
go/impl.go
go/logger.go
go/model__passenger_post_400_response.go
go/model_booking.go
go/model_booking_request.go
go/model_booking_status.go
go/model_car.go
go/model_driver_journey.go
go/model_driver_punctual_availabilities_request.go
go/model_driver_regular_availabilities_request.go
go/model_driver_trip.go
go/model_get_bookings_404_response.go
go/model_journey_schedule.go
go/model_passenger_trip_request.go
go/model_post_connections_request.go
go/model_preferences.go
go/model_price.go
go/model_punctual_availability_slot.go
go/model_regular_availability_slot.go
go/model_user.go
go/routers.go
main.go

View File

@ -0,0 +1 @@
7.0.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"context"
"net/http"
)
// BookingsFilterAPIRouter defines the required methods for binding the api requests to a responses for the BookingsFilterAPI
// The BookingsFilterAPIRouter implementation should parse necessary information from the http request,
// pass the data to a BookingsFilterAPIServicer to perform the required actions, then write the service results to the http response.
type BookingsFilterAPIRouter interface {
FilterBookingsByStatus(http.ResponseWriter, *http.Request)
}
// DriverAvailabilityAndScheduleAPIRouter defines the required methods for binding the api requests to a responses for the DriverAvailabilityAndScheduleAPI
// The DriverAvailabilityAndScheduleAPIRouter implementation should parse necessary information from the http request,
// pass the data to a DriverAvailabilityAndScheduleAPIServicer to perform the required actions, then write the service results to the http response.
type DriverAvailabilityAndScheduleAPIRouter interface {
DriverPunctualAvailabilitiesPost(http.ResponseWriter, *http.Request)
DriverRegularAvailabilitiesPost(http.ResponseWriter, *http.Request)
}
// InteractAPIRouter defines the required methods for binding the api requests to a responses for the InteractAPI
// The InteractAPIRouter implementation should parse necessary information from the http request,
// pass the data to a InteractAPIServicer to perform the required actions, then write the service results to the http response.
type InteractAPIRouter interface {
GetBookings(http.ResponseWriter, *http.Request)
PatchBookings(http.ResponseWriter, *http.Request)
PostBookings(http.ResponseWriter, *http.Request)
PostConnections(http.ResponseWriter, *http.Request)
}
// PassengerTripRequestAPIRouter defines the required methods for binding the api requests to a responses for the PassengerTripRequestAPI
// The PassengerTripRequestAPIRouter implementation should parse necessary information from the http request,
// pass the data to a PassengerTripRequestAPIServicer to perform the required actions, then write the service results to the http response.
type PassengerTripRequestAPIRouter interface {
PassengerPost(http.ResponseWriter, *http.Request)
}
// SearchAPIRouter defines the required methods for binding the api requests to a responses for the SearchAPI
// The SearchAPIRouter implementation should parse necessary information from the http request,
// pass the data to a SearchAPIServicer to perform the required actions, then write the service results to the http response.
type SearchAPIRouter interface {
GetDriverJourneys(http.ResponseWriter, *http.Request)
}
// BookingsFilterAPIServicer defines the api actions for the BookingsFilterAPI service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can be ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type BookingsFilterAPIServicer interface {
FilterBookingsByStatus(context.Context, string, string, string, string) (ImplResponse, error)
}
// DriverAvailabilityAndScheduleAPIServicer defines the api actions for the DriverAvailabilityAndScheduleAPI service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can be ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type DriverAvailabilityAndScheduleAPIServicer interface {
DriverPunctualAvailabilitiesPost(context.Context, DriverPunctualAvailabilitiesRequest) (ImplResponse, error)
DriverRegularAvailabilitiesPost(context.Context, DriverRegularAvailabilitiesRequest) (ImplResponse, error)
}
// InteractAPIServicer defines the api actions for the InteractAPI service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can be ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type InteractAPIServicer interface {
GetBookings(context.Context, string, string) (ImplResponse, error)
PatchBookings(context.Context, string, string, BookingStatus, string) (ImplResponse, error)
PostBookings(context.Context, BookingRequest) (ImplResponse, error)
PostConnections(context.Context, PostConnectionsRequest) (ImplResponse, error)
}
// PassengerTripRequestAPIServicer defines the api actions for the PassengerTripRequestAPI service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can be ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type PassengerTripRequestAPIServicer interface {
PassengerPost(context.Context, PassengerTripRequest) (ImplResponse, error)
}
// SearchAPIServicer defines the api actions for the SearchAPI service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can be ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type SearchAPIServicer interface {
GetDriverJourneys(context.Context, float32, float32, int32, string) (ImplResponse, error)
}

View File

@ -0,0 +1,82 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"net/http"
"strings"
)
// BookingsFilterAPIController binds http requests to an api service and writes the service results to the http response
type BookingsFilterAPIController struct {
service BookingsFilterAPIServicer
errorHandler ErrorHandler
}
// BookingsFilterAPIOption for how the controller is set up.
type BookingsFilterAPIOption func(*BookingsFilterAPIController)
// WithBookingsFilterAPIErrorHandler inject ErrorHandler into controller
func WithBookingsFilterAPIErrorHandler(h ErrorHandler) BookingsFilterAPIOption {
return func(c *BookingsFilterAPIController) {
c.errorHandler = h
}
}
// NewBookingsFilterAPIController creates a default api controller
func NewBookingsFilterAPIController(s BookingsFilterAPIServicer, opts ...BookingsFilterAPIOption) Router {
controller := &BookingsFilterAPIController{
service: s,
errorHandler: DefaultErrorHandler,
}
for _, opt := range opts {
opt(controller)
}
return controller
}
// Routes returns all the api routes for the BookingsFilterAPIController
func (c *BookingsFilterAPIController) Routes() Routes {
return Routes{
"FilterBookingsByStatus": Route{
strings.ToUpper("Get"),
"/bookings",
c.FilterBookingsByStatus,
},
}
}
// FilterBookingsByStatus - Filter and retrieve bookings by status, type, and ID.
func (c *BookingsFilterAPIController) FilterBookingsByStatus(w http.ResponseWriter, r *http.Request) {
authenticated := CheckOperatorAuthorization(r, AuthorizedOperators)
if !authenticated {
response := ImplResponse{
Code: 401,
Body: "Unauthorized request. Check your operator / API Key.",
}
EncodeJSONResponse(response.Body, &response.Code, w)
return
}
query := r.URL.Query()
operatorParam := query.Get("operator")
statusParam := query.Get("status")
filterTypeParam := query.Get("filterType")
idParam := query.Get("Id")
result, err := c.service.FilterBookingsByStatus(r.Context(), operatorParam, statusParam, filterTypeParam, idParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}

View File

@ -0,0 +1,111 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"context"
"fmt"
"github.com/spf13/viper"
"net/http"
"solidarity-service/handler"
"solidarity-service/internal"
"solidarity-service/storage"
"strings"
)
// BookingsFilterAPIService is a service that implements the logic for the BookingsFilterAPIServicer
// This service should implement the business logic for every endpoint for the BookingsFilterAPI API.
// Include any external packages or services that will be required by this service.
type BookingsFilterAPIService struct {
config *viper.Viper
handler *handler.SolidarityServiceHandler
storage storage.Storage
}
// NewBookingsFilterAPIService creates a default api service
func NewBookingsFilterAPIService(config *viper.Viper, handler *handler.SolidarityServiceHandler, storage storage.Storage) BookingsFilterAPIServicer {
return &BookingsFilterAPIService{
config: config,
handler: handler,
storage: storage,
}
}
// FilterBookingsByStatus - Filter and retrieve bookings by status, type, and ID.
func (s *BookingsFilterAPIService) FilterBookingsByStatus(ctx context.Context, operator string, status string, filterType string, id string) (ImplResponse, error) {
bookings, err := s.storage.FilterUserBookingsByStatus(filterType, internal.BookingStatus(status), id)
if err != nil {
fmt.Println(err)
if strings.Contains(err.Error(), " no rows in result set") {
return Response(http.StatusBadRequest, "ID not found in the database"), nil
} else {
return Response(http.StatusInternalServerError, nil), nil
}
}
responses := []Booking{}
for _, v := range bookings {
passenger, err := s.storage.GetPassenger(v.Passenger.ID)
if err != nil {
return Response(http.StatusInternalServerError, nil), nil
}
driver, err := s.storage.GetDriver(v.Driver.ID)
if err != nil {
return Response(http.StatusInternalServerError, nil), nil
}
duration, err := s.handler.CalculateDurationBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
if err != nil {
duration = 0
}
responses = append(responses, Booking{
Id: v.ID,
Status: BookingStatus(v.Status),
Driver: User{
Id: v.Driver.ID,
Operator: driver.Driver.Operator,
Alias: driver.Driver.Alias,
FirstName: driver.Driver.FirstName,
LastName: driver.Driver.LastName,
Grade: int32(driver.Driver.Grade),
Picture: driver.Driver.Picture,
Gender: driver.Driver.Gender,
VerifiedIdentity: driver.Driver.VerifiedIdentity,
},
Passenger: User{
Id: v.Passenger.ID,
Operator: passenger.Passenger.Operator,
Alias: passenger.Passenger.Alias,
FirstName: passenger.Passenger.FirstName,
LastName: passenger.Passenger.LastName,
Grade: int32(passenger.Passenger.Grade),
Picture: passenger.Passenger.Picture,
Gender: passenger.Passenger.Gender,
VerifiedIdentity: passenger.Passenger.VerifiedIdentity,
},
PassengerPickupDate: int32(passenger.Passenger_pickup_date),
PassengerPickupLat: passenger.Passenger_departure_address.Point().X(),
PassengerPickupLng: passenger.Passenger_departure_address.Point().Y(),
PassengerPickupAddress: passenger.Passenger_departure_address.Properties.MustString("name"),
PassengerDropLat: passenger.Passenger_destination_address.Point().X(),
PassengerDropLng: passenger.Passenger_destination_address.Point().Y(),
PassengerDropAddress: passenger.Passenger_destination_address.Properties.MustString("name"),
Duration: int32(duration),
Distance: int32(s.handler.CalculateDistanceBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)),
Car: Car{
Model: driver.Car.Model,
Brand: driver.Car.Brand,
},
Price: Price{
Type: "FREE",
},
})
}
return Response(200, responses), nil
}

View File

@ -0,0 +1,134 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"encoding/json"
"net/http"
"strings"
)
// DriverAvailabilityAndScheduleAPIController binds http requests to an api service and writes the service results to the http response
type DriverAvailabilityAndScheduleAPIController struct {
service DriverAvailabilityAndScheduleAPIServicer
errorHandler ErrorHandler
}
// DriverAvailabilityAndScheduleAPIOption for how the controller is set up.
type DriverAvailabilityAndScheduleAPIOption func(*DriverAvailabilityAndScheduleAPIController)
// WithDriverAvailabilityAndScheduleAPIErrorHandler inject ErrorHandler into controller
func WithDriverAvailabilityAndScheduleAPIErrorHandler(h ErrorHandler) DriverAvailabilityAndScheduleAPIOption {
return func(c *DriverAvailabilityAndScheduleAPIController) {
c.errorHandler = h
}
}
// NewDriverAvailabilityAndScheduleAPIController creates a default api controller
func NewDriverAvailabilityAndScheduleAPIController(s DriverAvailabilityAndScheduleAPIServicer, opts ...DriverAvailabilityAndScheduleAPIOption) Router {
controller := &DriverAvailabilityAndScheduleAPIController{
service: s,
errorHandler: DefaultErrorHandler,
}
for _, opt := range opts {
opt(controller)
}
return controller
}
// Routes returns all the api routes for the DriverAvailabilityAndScheduleAPIController
func (c *DriverAvailabilityAndScheduleAPIController) Routes() Routes {
return Routes{
"DriverPunctualAvailabilitiesPost": Route{
strings.ToUpper("Post"),
"/driver_punctual_availabilities",
c.DriverPunctualAvailabilitiesPost,
},
"DriverRegularAvailabilitiesPost": Route{
strings.ToUpper("Post"),
"/driver_regular_availabilities",
c.DriverRegularAvailabilitiesPost,
},
}
}
// DriverPunctualAvailabilitiesPost - Set Punctual Driver Availabilities
func (c *DriverAvailabilityAndScheduleAPIController) DriverPunctualAvailabilitiesPost(w http.ResponseWriter, r *http.Request) {
authenticated := CheckOperatorAuthorization(r, AuthorizedOperators)
if !authenticated {
response := ImplResponse{
Code: 401,
Body: "Unauthorized request. Check your operator / API Key.",
}
EncodeJSONResponse(response.Body, &response.Code, w)
return
}
driverPunctualAvailabilitiesRequestParam := DriverPunctualAvailabilitiesRequest{}
d := json.NewDecoder(r.Body)
d.DisallowUnknownFields()
if err := d.Decode(&driverPunctualAvailabilitiesRequestParam); err != nil {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
if err := AssertDriverPunctualAvailabilitiesRequestRequired(driverPunctualAvailabilitiesRequestParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
if err := AssertDriverPunctualAvailabilitiesRequestConstraints(driverPunctualAvailabilitiesRequestParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
result, err := c.service.DriverPunctualAvailabilitiesPost(r.Context(), driverPunctualAvailabilitiesRequestParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}
// DriverRegularAvailabilitiesPost - Set Regular Driver Availabilities
func (c *DriverAvailabilityAndScheduleAPIController) DriverRegularAvailabilitiesPost(w http.ResponseWriter, r *http.Request) {
authenticated := CheckOperatorAuthorization(r, AuthorizedOperators)
if !authenticated {
response := ImplResponse{
Code: 401,
Body: "Unauthorized request. Check your operator / API Key.",
}
EncodeJSONResponse(response.Body, &response.Code, w)
return
}
driverRegularAvailabilitiesRequestParam := DriverRegularAvailabilitiesRequest{}
d := json.NewDecoder(r.Body)
d.DisallowUnknownFields()
if err := d.Decode(&driverRegularAvailabilitiesRequestParam); err != nil {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
if err := AssertDriverRegularAvailabilitiesRequestRequired(driverRegularAvailabilitiesRequestParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
if err := AssertDriverRegularAvailabilitiesRequestConstraints(driverRegularAvailabilitiesRequestParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
result, err := c.service.DriverRegularAvailabilitiesPost(r.Context(), driverRegularAvailabilitiesRequestParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}

View File

@ -0,0 +1,127 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"context"
"errors"
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"
"github.com/spf13/viper"
"net/http"
"solidarity-service/handler"
"solidarity-service/internal"
"solidarity-service/storage"
)
// DriverAvailabilityAndScheduleAPIService is a service that implements the logic for the DriverAvailabilityAndScheduleAPIServicer
// This service should implement the business logic for every endpoint for the DriverAvailabilityAndScheduleAPI API.
// Include any external packages or services that will be required by this service.
type DriverAvailabilityAndScheduleAPIService struct {
config *viper.Viper
handler *handler.SolidarityServiceHandler
storage storage.Storage
}
// NewDriverAvailabilityAndScheduleAPIService creates a default api service
func NewDriverAvailabilityAndScheduleAPIService(config *viper.Viper, handler *handler.SolidarityServiceHandler, storage storage.Storage) DriverAvailabilityAndScheduleAPIServicer {
return &DriverAvailabilityAndScheduleAPIService{
config: config,
handler: handler,
storage: storage,
}
}
// DriverPunctualAvailabilitiesPost - Set Punctual Driver Availabilities
func (s *DriverAvailabilityAndScheduleAPIService) DriverPunctualAvailabilitiesPost(ctx context.Context, driverPunctualAvailabilitiesRequest DriverPunctualAvailabilitiesRequest) (ImplResponse, error) {
driver := internal.Driver{}
driver.Driver.ID = driverPunctualAvailabilitiesRequest.User.Id
driver.Driver.Operator = driverPunctualAvailabilitiesRequest.User.Operator
driver.Driver.Alias = driverPunctualAvailabilitiesRequest.User.Alias
driver.Driver.Grade = int64(driverPunctualAvailabilitiesRequest.User.Grade)
driver.Driver.Picture = driverPunctualAvailabilitiesRequest.User.Picture
driver.Driver.LastName = driverPunctualAvailabilitiesRequest.User.LastName
driver.Driver.FirstName = driverPunctualAvailabilitiesRequest.User.FirstName
driver.Driver.VerifiedIdentity = driverPunctualAvailabilitiesRequest.User.VerifiedIdentity
driver.Driver.Gender = driverPunctualAvailabilitiesRequest.User.Gender
driver.Preferences.Music = driverPunctualAvailabilitiesRequest.Preferences.Music
driver.Preferences.Is_talker = driverPunctualAvailabilitiesRequest.Preferences.IsTalker
driver.Preferences.Luggage_size = int64(driverPunctualAvailabilitiesRequest.Preferences.LuggageSize)
driver.Preferences.Smoking = driverPunctualAvailabilitiesRequest.Preferences.Smoking
driver.Preferences.Animals = driverPunctualAvailabilitiesRequest.Preferences.Animals
driver.Driver_departure_address = &geojson.Feature{
Type: "Feature",
Geometry: orb.Geometry(orb.Point{driverPunctualAvailabilitiesRequest.Latitude, driverPunctualAvailabilitiesRequest.Longitude}),
Properties: geojson.Properties{
"name": driverPunctualAvailabilitiesRequest.Address,
},
}
driver.Radius = driverPunctualAvailabilitiesRequest.Radius
driver.AvailabilitiesType = internal.Punctual
for _, v := range driverPunctualAvailabilitiesRequest.Availabilities {
driver.PunctualAvailabilities = append(driver.PunctualAvailabilities, internal.PunctualAvailabilities{
Date: int64(v.Date),
StartTime: v.StartTime,
EndTime: v.EndTime,
})
}
driver.Car.Brand = driverPunctualAvailabilitiesRequest.Car.Brand
driver.Car.Model = driverPunctualAvailabilitiesRequest.Car.Model
err := s.storage.CreateDriver(driver)
if err != nil {
return Response(http.StatusInternalServerError, nil), errors.New("DriverPunctualAvailabilitiesPost internal server error")
} else {
return Response(201, "Punctual driver availabilities set successfully"), nil
}
}
// DriverRegularAvailabilitiesPost - Set Regular Driver Availabilities
func (s *DriverAvailabilityAndScheduleAPIService) DriverRegularAvailabilitiesPost(ctx context.Context, driverRegularAvailabilitiesRequest DriverRegularAvailabilitiesRequest) (ImplResponse, error) {
driver := internal.Driver{}
driver.Driver.ID = driverRegularAvailabilitiesRequest.User.Id
driver.Driver.Operator = driverRegularAvailabilitiesRequest.User.Operator
driver.Driver.Alias = driverRegularAvailabilitiesRequest.User.Alias
driver.Driver.Grade = int64(driverRegularAvailabilitiesRequest.User.Grade)
driver.Driver.Picture = driverRegularAvailabilitiesRequest.User.Picture
driver.Driver.LastName = driverRegularAvailabilitiesRequest.User.LastName
driver.Driver.FirstName = driverRegularAvailabilitiesRequest.User.FirstName
driver.Driver.VerifiedIdentity = driverRegularAvailabilitiesRequest.User.VerifiedIdentity
driver.Driver.Gender = driverRegularAvailabilitiesRequest.User.Gender
driver.Driver_departure_address = &geojson.Feature{
Type: "Feature",
Geometry: orb.Geometry(orb.Point{driverRegularAvailabilitiesRequest.Latitude, driverRegularAvailabilitiesRequest.Longitude}),
Properties: geojson.Properties{
"name": driverRegularAvailabilitiesRequest.Address,
},
}
driver.Preferences.Music = driverRegularAvailabilitiesRequest.Preferences.Music
driver.Preferences.Is_talker = driverRegularAvailabilitiesRequest.Preferences.IsTalker
driver.Preferences.Luggage_size = int64(driverRegularAvailabilitiesRequest.Preferences.LuggageSize)
driver.Preferences.Smoking = driverRegularAvailabilitiesRequest.Preferences.Smoking
driver.Preferences.Animals = driverRegularAvailabilitiesRequest.Preferences.Animals
driver.Radius = driverRegularAvailabilitiesRequest.Radius
driver.AvailabilitiesType = internal.Regular
for _, v := range driverRegularAvailabilitiesRequest.Availabilities {
driver.RegularAvailabilities = append(driver.RegularAvailabilities, internal.RegularAvailabilities{
DayOfWeek: v.DayOfWeek,
StartTime: v.StartTime,
EndTime: v.EndTime,
})
}
driver.Car.Brand = driverRegularAvailabilitiesRequest.Car.Brand
driver.Car.Model = driverRegularAvailabilitiesRequest.Car.Model
err := s.storage.CreateDriver(driver)
if err != nil {
return Response(http.StatusInternalServerError, nil), errors.New("DriverPunctualAvailabilitiesPost internal server error")
} else {
return Response(201, "Regular driver availabilities set successfully"), nil
}
}

View File

@ -0,0 +1,190 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"encoding/json"
"errors"
"github.com/gorilla/mux"
"io"
"net/http"
"strings"
)
// InteractAPIController binds http requests to an api service and writes the service results to the http response
type InteractAPIController struct {
service InteractAPIServicer
errorHandler ErrorHandler
}
// InteractAPIOption for how the controller is set up.
type InteractAPIOption func(*InteractAPIController)
// WithInteractAPIErrorHandler inject ErrorHandler into controller
func WithInteractAPIErrorHandler(h ErrorHandler) InteractAPIOption {
return func(c *InteractAPIController) {
c.errorHandler = h
}
}
// NewInteractAPIController creates a default api controller
func NewInteractAPIController(s InteractAPIServicer, opts ...InteractAPIOption) Router {
controller := &InteractAPIController{
service: s,
errorHandler: DefaultErrorHandler,
}
for _, opt := range opts {
opt(controller)
}
return controller
}
// Routes returns all the api routes for the InteractAPIController
func (c *InteractAPIController) Routes() Routes {
return Routes{
"GetBookings": Route{
strings.ToUpper("Get"),
"/bookings/{bookingId}",
c.GetBookings,
},
"PatchBookings": Route{
strings.ToUpper("Patch"),
"/bookings/{bookingId}",
c.PatchBookings,
},
"PostBookings": Route{
strings.ToUpper("Post"),
"/bookings",
c.PostBookings,
},
"PostConnections": Route{
strings.ToUpper("Post"),
"/messages",
c.PostConnections,
},
}
}
// GetBookings - Retrieves an existing Booking request.
func (c *InteractAPIController) GetBookings(w http.ResponseWriter, r *http.Request) {
authenticated := CheckOperatorAuthorization(r, AuthorizedOperators)
if !authenticated {
response := ImplResponse{
Code: 401,
Body: "Unauthorized request. Check your operator / API Key.",
}
EncodeJSONResponse(response.Body, &response.Code, w)
return
}
params := mux.Vars(r)
query := r.URL.Query()
operatorParam := query.Get("operator")
bookingIdParam := params["bookingId"]
result, err := c.service.GetBookings(r.Context(), operatorParam, bookingIdParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}
// PatchBookings - Updates status of an existing Booking request.
func (c *InteractAPIController) PatchBookings(w http.ResponseWriter, r *http.Request) {
authenticated := CheckOperatorAuthorization(r, AuthorizedOperators)
if !authenticated {
response := ImplResponse{
Code: 401,
Body: "Unauthorized request. Check your operator / API Key.",
}
EncodeJSONResponse(response.Body, &response.Code, w)
return
}
params := mux.Vars(r)
query := r.URL.Query()
operatorParam := query.Get("operator")
bookingIdParam := params["bookingId"]
statusParam := query.Get("status")
messageParam := query.Get("message")
result, err := c.service.PatchBookings(r.Context(), operatorParam, bookingIdParam, BookingStatus(statusParam), messageParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}
// PostBookings - Create a punctual outward Booking request.
func (c *InteractAPIController) PostBookings(w http.ResponseWriter, r *http.Request) {
authenticated := CheckOperatorAuthorization(r, AuthorizedOperators)
if !authenticated {
response := ImplResponse{
Code: 401,
Body: "Unauthorized request. Check your operator / API Key.",
}
EncodeJSONResponse(response.Body, &response.Code, w)
return
}
bookingRequestParam := BookingRequest{}
d := json.NewDecoder(r.Body)
d.DisallowUnknownFields()
if err := d.Decode(&bookingRequestParam); err != nil && !errors.Is(err, io.EOF) {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
if err := AssertBookingRequestRequired(bookingRequestParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
if err := AssertBookingRequestConstraints(bookingRequestParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
result, err := c.service.PostBookings(r.Context(), bookingRequestParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}
// PostConnections - Send a message to the owner of a retrieved journey.
func (c *InteractAPIController) PostConnections(w http.ResponseWriter, r *http.Request) {
postConnectionsRequestParam := PostConnectionsRequest{}
d := json.NewDecoder(r.Body)
d.DisallowUnknownFields()
if err := d.Decode(&postConnectionsRequestParam); err != nil && !errors.Is(err, io.EOF) {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
if err := AssertPostConnectionsRequestRequired(postConnectionsRequestParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
if err := AssertPostConnectionsRequestConstraints(postConnectionsRequestParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
result, err := c.service.PostConnections(r.Context(), postConnectionsRequestParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}

View File

@ -0,0 +1,196 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"context"
"errors"
"fmt"
"github.com/spf13/viper"
"net/http"
"solidarity-service/handler"
"solidarity-service/internal"
"solidarity-service/storage"
"strings"
)
// InteractAPIService is a service that implements the logic for the InteractAPIServicer
// This service should implement the business logic for every endpoint for the InteractAPI API.
// Include any external packages or services that will be required by this service.
type InteractAPIService struct {
config *viper.Viper
handler *handler.SolidarityServiceHandler
storage storage.Storage
}
// NewInteractAPIService creates a default api service
func NewInteractAPIService(config *viper.Viper, handler *handler.SolidarityServiceHandler, storage storage.Storage) InteractAPIServicer {
return &InteractAPIService{
config: config,
handler: handler,
storage: storage,
}
}
// GetBookings - Retrieves an existing Booking request.
func (s *InteractAPIService) GetBookings(ctx context.Context, operator string, bookingId string) (ImplResponse, error) {
booking, err := s.storage.GetBooking(bookingId)
if err != nil {
if strings.Contains(err.Error(), " no rows in result set") {
return Response(http.StatusBadRequest, "ID not found in the database"), nil
} else {
return Response(http.StatusInternalServerError, nil), errors.New("DriverPunctualAvailabilitiesPost internal server error")
}
}
passenger, err := s.storage.GetPassenger(booking.Passenger.ID)
if err != nil {
return Response(http.StatusInternalServerError, nil), nil
}
driver, err := s.storage.GetDriver(booking.Driver.ID)
if err != nil {
return Response(http.StatusInternalServerError, nil), nil
}
duration, err := s.handler.CalculateDurationBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
if err != nil {
duration = 0
}
response := Booking{
Id: booking.ID,
Driver: User{
Id: driver.Driver.ID,
Operator: driver.Driver.Operator,
Alias: driver.Driver.Alias,
FirstName: driver.Driver.FirstName,
LastName: driver.Driver.LastName,
Grade: int32(driver.Driver.Grade),
Picture: driver.Driver.Picture,
Gender: driver.Driver.Gender,
VerifiedIdentity: driver.Driver.VerifiedIdentity,
},
Passenger: User{
Id: passenger.Passenger.ID,
Operator: passenger.Passenger.Operator,
Alias: passenger.Passenger.Alias,
FirstName: passenger.Passenger.FirstName,
LastName: passenger.Passenger.LastName,
Grade: int32(passenger.Passenger.Grade),
Picture: passenger.Passenger.Picture,
Gender: passenger.Passenger.Gender,
VerifiedIdentity: passenger.Passenger.VerifiedIdentity,
},
PassengerPickupDate: int32(passenger.Passenger_pickup_date),
PassengerPickupLat: passenger.Passenger_departure_address.Point().X(),
PassengerPickupLng: passenger.Passenger_departure_address.Point().Y(),
PassengerPickupAddress: passenger.Passenger_departure_address.Properties.MustString("name"),
PassengerDropLat: passenger.Passenger_destination_address.Point().X(),
PassengerDropLng: passenger.Passenger_destination_address.Point().Y(),
PassengerDropAddress: passenger.Passenger_destination_address.Properties.MustString("name"),
Status: BookingStatus(booking.Status),
Duration: int32(duration),
Distance: int32(s.handler.CalculateDistanceBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)),
Car: Car{
Model: driver.Car.Model,
Brand: driver.Car.Brand,
},
Price: Price{
Type: "FREE",
},
}
fmt.Println(response)
return Response(200, response), nil
}
// PatchBookings - Updates status of an existing Booking request.
func (s *InteractAPIService) PatchBookings(ctx context.Context, operator string, bookingId string, status BookingStatus, message string) (ImplResponse, error) {
err := s.storage.UpdateBookingStatus(bookingId, internal.BookingStatus(status))
fmt.Println(err)
if err != nil {
if strings.Contains(err.Error(), " no rows in result set") {
return Response(http.StatusBadRequest, "ID not found in the database"), nil
}
return Response(http.StatusInternalServerError, nil), nil
}
return Response(200, "Successful operation"), nil
}
// PostBookings - Create a punctual outward Booking request.
func (s *InteractAPIService) PostBookings(ctx context.Context, bookingRequest BookingRequest) (ImplResponse, error) {
booking := internal.BookingRequest{}
booking.ID = bookingRequest.Id
booking.Status = internal.BookingStatus(bookingRequest.Status)
booking.Driver_id = bookingRequest.DriverId
booking.Passenger_id = bookingRequest.PassengerId
booking.Operator = bookingRequest.Operator
err := s.storage.CreateBooking(booking)
if err != nil {
return Response(http.StatusInternalServerError, nil), errors.New("PostBookings internal server error")
}
passenger, err := s.storage.GetPassenger(booking.Passenger_id)
if err != nil {
return Response(http.StatusInternalServerError, nil), errors.New("PostBookings internal server error")
}
driver, err := s.storage.GetDriver(booking.Driver_id)
if err != nil {
return Response(http.StatusInternalServerError, nil), errors.New("PostBookings internal server error")
}
duration, err := s.handler.CalculateDurationBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
if err != nil {
duration = 0
}
response := Booking{
Id: bookingRequest.Id,
Driver: User{
Id: driver.Driver.ID,
Operator: driver.Driver.Operator,
Alias: driver.Driver.Alias,
FirstName: driver.Driver.FirstName,
LastName: driver.Driver.LastName,
Grade: int32(driver.Driver.Grade),
Picture: driver.Driver.Picture,
Gender: driver.Driver.Gender,
VerifiedIdentity: driver.Driver.VerifiedIdentity,
},
Passenger: User{
Id: passenger.Passenger.ID,
Operator: passenger.Passenger.Operator,
Alias: passenger.Passenger.Alias,
FirstName: passenger.Passenger.FirstName,
LastName: passenger.Passenger.LastName,
Grade: int32(passenger.Passenger.Grade),
Picture: passenger.Passenger.Picture,
Gender: passenger.Passenger.Gender,
VerifiedIdentity: passenger.Passenger.VerifiedIdentity,
},
PassengerPickupDate: int32(passenger.Passenger_pickup_date),
PassengerPickupLat: passenger.Passenger_departure_address.Point().X(),
PassengerPickupLng: passenger.Passenger_departure_address.Point().Y(),
PassengerPickupAddress: passenger.Passenger_departure_address.Properties.MustString("name"),
PassengerDropLat: passenger.Passenger_destination_address.Point().X(),
PassengerDropLng: passenger.Passenger_destination_address.Point().Y(),
PassengerDropAddress: passenger.Passenger_destination_address.Properties.MustString("name"),
Status: bookingRequest.Status,
Duration: int32(duration),
Distance: int32(s.handler.CalculateDistanceBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)),
Car: Car{
Model: driver.Car.Model,
Brand: driver.Car.Brand,
},
Price: Price{
Type: "FREE",
},
}
return Response(201, response), nil
}
// PostConnections - Send a message to the owner of a retrieved journey.
func (s *InteractAPIService) PostConnections(ctx context.Context, postConnectionsRequest PostConnectionsRequest) (ImplResponse, error) {
return Response(http.StatusNotImplemented, nil), errors.New("PostConnections method not implemented")
}

View File

@ -0,0 +1,93 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"encoding/json"
"net/http"
"strings"
)
// PassengerTripRequestAPIController binds http requests to an api service and writes the service results to the http response
type PassengerTripRequestAPIController struct {
service PassengerTripRequestAPIServicer
errorHandler ErrorHandler
}
// PassengerTripRequestAPIOption for how the controller is set up.
type PassengerTripRequestAPIOption func(*PassengerTripRequestAPIController)
// WithPassengerTripRequestAPIErrorHandler inject ErrorHandler into controller
func WithPassengerTripRequestAPIErrorHandler(h ErrorHandler) PassengerTripRequestAPIOption {
return func(c *PassengerTripRequestAPIController) {
c.errorHandler = h
}
}
// NewPassengerTripRequestAPIController creates a default api controller
func NewPassengerTripRequestAPIController(s PassengerTripRequestAPIServicer, opts ...PassengerTripRequestAPIOption) Router {
controller := &PassengerTripRequestAPIController{
service: s,
errorHandler: DefaultErrorHandler,
}
for _, opt := range opts {
opt(controller)
}
return controller
}
// Routes returns all the api routes for the PassengerTripRequestAPIController
func (c *PassengerTripRequestAPIController) Routes() Routes {
return Routes{
"PassengerPost": Route{
strings.ToUpper("Post"),
"/passenger",
c.PassengerPost,
},
}
}
// PassengerPost - Create a Passenger Trip Request
func (c *PassengerTripRequestAPIController) PassengerPost(w http.ResponseWriter, r *http.Request) {
authenticated := CheckOperatorAuthorization(r, AuthorizedOperators)
if !authenticated {
response := ImplResponse{
Code: 401,
Body: "Unauthorized request. Check your operator / API Key.",
}
EncodeJSONResponse(response.Body, &response.Code, w)
return
}
passengerTripRequestParam := PassengerTripRequest{}
d := json.NewDecoder(r.Body)
d.DisallowUnknownFields()
if err := d.Decode(&passengerTripRequestParam); err != nil {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
if err := AssertPassengerTripRequestRequired(passengerTripRequestParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
if err := AssertPassengerTripRequestConstraints(passengerTripRequestParam); err != nil {
c.errorHandler(w, r, err, nil)
return
}
result, err := c.service.PassengerPost(r.Context(), passengerTripRequestParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}

View File

@ -0,0 +1,80 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"context"
"errors"
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"
"github.com/spf13/viper"
"net/http"
"solidarity-service/handler"
"solidarity-service/internal"
"solidarity-service/storage"
)
// PassengerTripRequestAPIService is a service that implements the logic for the PassengerTripRequestAPIServicer
// This service should implement the business logic for every endpoint for the PassengerTripRequestAPI API.
// Include any external packages or services that will be required by this service.
type PassengerTripRequestAPIService struct {
config *viper.Viper
handler *handler.SolidarityServiceHandler
storage storage.Storage
}
// NewPassengerTripRequestAPIService creates a default api service
func NewPassengerTripRequestAPIService(config *viper.Viper, handler *handler.SolidarityServiceHandler, storage storage.Storage) PassengerTripRequestAPIServicer {
return &PassengerTripRequestAPIService{
config: config,
handler: handler,
storage: storage,
}
}
// PassengerPost - Create a Passenger Trip Request
func (s *PassengerTripRequestAPIService) PassengerPost(ctx context.Context, passengerTripRequest PassengerTripRequest) (ImplResponse, error) {
passenger := internal.Passenger{}
passenger.Passenger_departure_address = &geojson.Feature{
Type: "Feature",
Geometry: orb.Geometry(orb.Point{passengerTripRequest.DepartureLatitude, passengerTripRequest.DepartureLongitude}),
Properties: geojson.Properties{
"name": passengerTripRequest.DepartureAddress,
},
}
passenger.Passenger_destination_address = &geojson.Feature{
Type: "Feature",
Geometry: orb.Geometry(orb.Point{passengerTripRequest.DestinationLatitude, passengerTripRequest.DestinationLongitude}),
Properties: geojson.Properties{
"name": passengerTripRequest.DestinationAddress,
},
}
passenger.Passenger_pickup_date = int64(passengerTripRequest.DepartureDate)
passenger.Passenger.ID = passengerTripRequest.User.Id
passenger.Passenger.Operator = passengerTripRequest.User.Operator
passenger.Passenger.Alias = passengerTripRequest.User.Alias
passenger.Passenger.FirstName = passengerTripRequest.User.FirstName
passenger.Passenger.LastName = passengerTripRequest.User.LastName
passenger.Passenger.Picture = passengerTripRequest.User.Picture
passenger.Passenger.Grade = int64(passengerTripRequest.User.Grade)
passenger.Passenger.Gender = passengerTripRequest.User.Gender
passenger.Passenger.VerifiedIdentity = passengerTripRequest.User.VerifiedIdentity
passenger.Preferences.Animals = passengerTripRequest.Preferences.Animals
passenger.Preferences.Luggage_size = int64(passengerTripRequest.Preferences.LuggageSize)
passenger.Preferences.Smoking = passengerTripRequest.Preferences.Smoking
passenger.Preferences.Is_talker = passengerTripRequest.Preferences.IsTalker
passenger.Preferences.Music = passengerTripRequest.Preferences.Music
err := s.storage.CreatePassenger(passenger)
if err != nil {
return Response(http.StatusInternalServerError, nil), errors.New("DriverPunctualAvailabilitiesPost internal server error")
} else {
return Response(201, "Trip request created"), nil
}
}

View File

@ -0,0 +1,103 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"net/http"
"strings"
)
// SearchAPIController binds http requests to an api service and writes the service results to the http response
type SearchAPIController struct {
service SearchAPIServicer
errorHandler ErrorHandler
}
// SearchAPIOption for how the controller is set up.
type SearchAPIOption func(*SearchAPIController)
// WithSearchAPIErrorHandler inject ErrorHandler into controller
func WithSearchAPIErrorHandler(h ErrorHandler) SearchAPIOption {
return func(c *SearchAPIController) {
c.errorHandler = h
}
}
// NewSearchAPIController creates a default api controller
func NewSearchAPIController(s SearchAPIServicer, opts ...SearchAPIOption) Router {
controller := &SearchAPIController{
service: s,
errorHandler: DefaultErrorHandler,
}
for _, opt := range opts {
opt(controller)
}
return controller
}
// Routes returns all the api routes for the SearchAPIController
func (c *SearchAPIController) Routes() Routes {
return Routes{
"GetDriverJourneys": Route{
strings.ToUpper("Get"),
"/driver_journeys",
c.GetDriverJourneys,
},
}
}
// GetDriverJourneys - Search for matching punctual planned outward driver journeys.
func (c *SearchAPIController) GetDriverJourneys(w http.ResponseWriter, r *http.Request) {
authenticated := CheckOperatorAuthorization(r, AuthorizedOperators)
if !authenticated {
response := ImplResponse{
Code: 401,
Body: "Unauthorized request. Check your operator / API Key.",
}
EncodeJSONResponse(response.Body, &response.Code, w)
return
}
query := r.URL.Query()
departureLatParam, err := parseNumericParameter[float32](
query.Get("departureLat"),
WithRequire[float32](parseFloat32),
)
if err != nil {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
departureLngParam, err := parseNumericParameter[float32](
query.Get("departureLng"),
WithRequire[float32](parseFloat32),
)
if err != nil {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
departureDateParam, err := parseNumericParameter[int32](
query.Get("departureDate"),
WithRequire[int32](parseInt32),
)
if err != nil {
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
return
}
operatorParam := query.Get("operator")
result, err := c.service.GetDriverJourneys(r.Context(), departureLatParam, departureLngParam, departureDateParam, operatorParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}

View File

@ -0,0 +1,105 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"context"
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"
"github.com/spf13/viper"
"net/http"
"solidarity-service/handler"
"solidarity-service/internal"
"solidarity-service/storage"
"strings"
)
// SearchAPIService is a service that implements the logic for the SearchAPIServicer
// This service should implement the business logic for every endpoint for the SearchAPI API.
// Include any external packages or services that will be required by this service.
type SearchAPIService struct {
config *viper.Viper
handler *handler.SolidarityServiceHandler
storage storage.Storage
}
// NewSearchAPIService creates a default api service
func NewSearchAPIService(config *viper.Viper, handler *handler.SolidarityServiceHandler, storage storage.Storage) SearchAPIServicer {
return &SearchAPIService{
config: config,
handler: handler,
storage: storage,
}
}
// GetDriverJourneys - Search for matching punctual planned outward driver journeys.
func (s *SearchAPIService) GetDriverJourneys(ctx context.Context, departureLat float32, departureLng float32, departureDate int32, operator string) (ImplResponse, error) {
drivers, err := s.storage.DriverJourneys(&geojson.Feature{
Type: "Feature",
Geometry: orb.Geometry(orb.Point{float64(departureLat), float64(departureLng)}),
}, int64(departureDate))
if err != nil {
if strings.Contains(err.Error(), " no rows in result set") {
return Response(http.StatusBadRequest, "ID not found in the database"), nil
} else {
return Response(http.StatusInternalServerError, nil), nil
}
}
response := []DriverJourney{}
for _, v := range drivers {
temp := DriverJourney{}
if v.AvailabilitiesType == internal.Regular && v.RegularAvailabilities != nil {
for _, v := range v.RegularAvailabilities {
temp.RegularAvailabilitySlot = append(temp.RegularAvailabilitySlot, RegularAvailabilitySlot{
DayOfWeek: v.DayOfWeek,
StartTime: v.StartTime,
EndTime: v.EndTime,
})
}
} else if v.AvailabilitiesType == internal.Punctual && v.PunctualAvailabilities != nil {
for _, v := range v.PunctualAvailabilities {
temp.PunctualAvailabilitySlot = append(temp.PunctualAvailabilitySlot, PunctualAvailabilitySlot{
Date: int32(v.Date),
StartTime: v.StartTime,
EndTime: v.EndTime,
})
}
}
tamp := DriverJourney{
User: User{
Id: v.Driver.ID,
Operator: v.Driver.Operator,
Alias: v.Driver.Alias,
FirstName: v.Driver.FirstName,
LastName: v.Driver.LastName,
Grade: int32(v.Driver.Grade),
Picture: v.Driver.Picture,
Gender: v.Driver.Gender,
VerifiedIdentity: v.Driver.VerifiedIdentity,
},
Car: Car{
Model: v.Car.Model,
Brand: v.Car.Brand,
},
DriverDepartureDate: int64(departureDate),
Price: Price{
Type: "FREE",
},
DriverDepartureAddress: v.Driver_departure_address.Properties.MustString("name"),
}
temp.DriverDepartureAddress = tamp.DriverDepartureAddress
temp.Car = tamp.Car
temp.User = tamp.User
temp.DriverDepartureDate = tamp.DriverDepartureDate
temp.Price = tamp.Price
response = append(response, temp)
}
return Response(200, response), nil
}

View File

@ -0,0 +1,62 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"errors"
"fmt"
"net/http"
)
var (
// ErrTypeAssertionError is thrown when type an interface does not match the asserted type
ErrTypeAssertionError = errors.New("unable to assert type")
)
// ParsingError indicates that an error has occurred when parsing request parameters
type ParsingError struct {
Err error
}
func (e *ParsingError) Unwrap() error {
return e.Err
}
func (e *ParsingError) Error() string {
return e.Err.Error()
}
// RequiredError indicates that an error has occurred when parsing request parameters
type RequiredError struct {
Field string
}
func (e *RequiredError) Error() string {
return fmt.Sprintf("required field '%s' is zero value.", e.Field)
}
// ErrorHandler defines the required method for handling error. You may implement it and inject this into a controller if
// you would like errors to be handled differently from the DefaultErrorHandler
type ErrorHandler func(w http.ResponseWriter, r *http.Request, err error, result *ImplResponse)
// DefaultErrorHandler defines the default logic on how to handle errors from the controller. Any errors from parsing
// request params will return a StatusBadRequest. Otherwise, the error code originating from the servicer will be used.
func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, err error, result *ImplResponse) {
if _, ok := err.(*ParsingError); ok {
// Handle parsing errors
EncodeJSONResponse(err.Error(), func(i int) *int { return &i }(http.StatusBadRequest), w)
} else if _, ok := err.(*RequiredError); ok {
// Handle missing required errors
EncodeJSONResponse(err.Error(), func(i int) *int { return &i }(http.StatusUnprocessableEntity), w)
} else {
// Handle all other errors
EncodeJSONResponse(err.Error(), &result.Code, w)
}
}

View File

@ -0,0 +1,60 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"reflect"
)
// Response return a ImplResponse struct filled
func Response(code int, body interface{}) ImplResponse {
return ImplResponse {
Code: code,
Body: body,
}
}
// IsZeroValue checks if the val is the zero-ed value.
func IsZeroValue(val interface{}) bool {
return val == nil || reflect.DeepEqual(val, reflect.Zero(reflect.TypeOf(val)).Interface())
}
// AssertRecurseInterfaceRequired recursively checks each struct in a slice against the callback.
// This method traverse nested slices in a preorder fashion.
func AssertRecurseInterfaceRequired[T any](obj interface{}, callback func(T) error) error {
return AssertRecurseValueRequired(reflect.ValueOf(obj), callback)
}
// AssertRecurseValueRequired checks each struct in the nested slice against the callback.
// This method traverse nested slices in a preorder fashion. ErrTypeAssertionError is thrown if
// the underlying struct does not match type T.
func AssertRecurseValueRequired[T any](value reflect.Value, callback func(T) error) error {
switch value.Kind() {
// If it is a struct we check using callback
case reflect.Struct:
obj, ok := value.Interface().(T)
if !ok {
return ErrTypeAssertionError
}
if err := callback(obj); err != nil {
return err
}
// If it is a slice we continue recursion
case reflect.Slice:
for i := 0; i < value.Len(); i += 1 {
if err := AssertRecurseValueRequired(value.Index(i), callback); err != nil {
return err
}
}
}
return nil
}

View File

@ -0,0 +1,16 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
// ImplResponse defines an implementation response with error code and the associated body
type ImplResponse struct {
Code int
Body interface{}
}

View File

@ -0,0 +1,32 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"log"
"net/http"
"time"
)
func Logger(inner http.Handler, name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
inner.ServeHTTP(w, r)
log.Printf(
"%s %s %s %s",
r.Method,
r.RequestURI,
name,
time.Since(start),
)
})
}

View File

@ -0,0 +1,28 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type PassengerPost400Response struct {
Error string `json:"error,omitempty"`
}
// AssertPassengerPost400ResponseRequired checks if the required fields are not zero-ed
func AssertPassengerPost400ResponseRequired(obj PassengerPost400Response) error {
return nil
}
// AssertPassengerPost400ResponseConstraints checks if the values respects the defined constraints
func AssertPassengerPost400ResponseConstraints(obj PassengerPost400Response) error {
return nil
}

View File

@ -0,0 +1,93 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type Booking struct {
// Booking id is common between both operators, and must be created as a [UUID](https://datatracker.ietf.org/doc/html/rfc4122) by whoever initiates the booking. Usage of a [4 UUID](https://datatracker.ietf.org/doc/html/rfc4122#section-4.4) generation algorithm is advised.
Id string `json:"id"`
Driver User `json:"driver"`
Passenger User `json:"passenger"`
// Passenger pickup datetime as a UNIX UTC timestamp in seconds.
PassengerPickupDate int32 `json:"passengerPickupDate"`
// Latitude of the passenger pick-up point.
PassengerPickupLat float64 `json:"passengerPickupLat"`
// Longitude of the passenger pick-up point.
PassengerPickupLng float64 `json:"passengerPickupLng"`
// Latitude of the passenger drop-off point.
PassengerDropLat float64 `json:"passengerDropLat"`
// Longitude of the passenger drop-off point.
PassengerDropLng float64 `json:"passengerDropLng"`
// String representing the pickup-up address.
PassengerPickupAddress string `json:"passengerPickupAddress,omitempty"`
// String representing the drop-off address.
PassengerDropAddress string `json:"passengerDropAddress,omitempty"`
Status BookingStatus `json:"status"`
// Carpooling duration in seconds.
Duration int32 `json:"duration,omitempty"`
// Carpooling distance in meters.
Distance int32 `json:"distance,omitempty"`
Price Price `json:"price"`
Car Car `json:"car,omitempty"`
}
// AssertBookingRequired checks if the required fields are not zero-ed
func AssertBookingRequired(obj Booking) error {
elements := map[string]interface{}{
"id": obj.Id,
"driver": obj.Driver,
"passenger": obj.Passenger,
"passengerPickupDate": obj.PassengerPickupDate,
"passengerPickupLat": obj.PassengerPickupLat,
"passengerPickupLng": obj.PassengerPickupLng,
"passengerDropLat": obj.PassengerDropLat,
"passengerDropLng": obj.PassengerDropLng,
"status": obj.Status,
"price": obj.Price,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
if err := AssertUserRequired(obj.Driver); err != nil {
return err
}
if err := AssertUserRequired(obj.Passenger); err != nil {
return err
}
if err := AssertPriceRequired(obj.Price); err != nil {
return err
}
if err := AssertCarRequired(obj.Car); err != nil {
return err
}
return nil
}
// AssertBookingConstraints checks if the values respects the defined constraints
func AssertBookingConstraints(obj Booking) error {
return nil
}

View File

@ -0,0 +1,50 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type BookingRequest struct {
// Booking id is common between both operators, and must be created as a [UUID](https://datatracker.ietf.org/doc/html/rfc4122) by whoever initiates the booking. Usage of a [4 UUID](https://datatracker.ietf.org/doc/html/rfc4122#section-4.4) generation algorithm is advised.
Id string `json:"id"`
PassengerId string `json:"passengerId"`
DriverId string `json:"driverId"`
Status BookingStatus `json:"status"`
Operator string `json:"operator"`
}
// AssertBookingRequestRequired checks if the required fields are not zero-ed
func AssertBookingRequestRequired(obj BookingRequest) error {
elements := map[string]interface{}{
"id": obj.Id,
"passengerId": obj.PassengerId,
"driverId": obj.DriverId,
"status": obj.Status,
"operator": obj.Operator,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
return nil
}
// AssertBookingRequestConstraints checks if the values respects the defined constraints
func AssertBookingRequestConstraints(obj BookingRequest) error {
return nil
}

View File

@ -0,0 +1,35 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
// BookingStatus : Status of the booking.
type BookingStatus string
// List of BookingStatus
const (
WAITING_DRIVER_CONFIRMATION BookingStatus = "WAITING_DRIVER_CONFIRMATION"
WAITING_PASSENGER_CONFIRMATION BookingStatus = "WAITING_PASSENGER_CONFIRMATION"
CONFIRMED BookingStatus = "CONFIRMED"
CANCELLED BookingStatus = "CANCELLED"
COMPLETED_PENDING_VALIDATION BookingStatus = "COMPLETED_PENDING_VALIDATION"
VALIDATED BookingStatus = "VALIDATED"
)
// AssertBookingStatusRequired checks if the required fields are not zero-ed
func AssertBookingStatusRequired(obj BookingStatus) error {
return nil
}
// AssertBookingStatusConstraints checks if the values respects the defined constraints
func AssertBookingStatusConstraints(obj BookingStatus) error {
return nil
}

View File

@ -0,0 +1,32 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type Car struct {
// Model of the car.
Model string `json:"model,omitempty"`
// Brand of the car.
Brand string `json:"brand,omitempty"`
}
// AssertCarRequired checks if the required fields are not zero-ed
func AssertCarRequired(obj Car) error {
return nil
}
// AssertCarConstraints checks if the values respects the defined constraints
func AssertCarConstraints(obj Car) error {
return nil
}

View File

@ -0,0 +1,51 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type DriverJourney struct {
User User `json:"user"`
Car Car `json:"car,omitempty"`
RegularAvailabilitySlot []RegularAvailabilitySlot `json:"regular_availabilities,omitempty"`
PunctualAvailabilitySlot []PunctualAvailabilitySlot `json:"punctual_availabilities,omitempty"`
// Driver departure datetime as a UNIX UTC timestamp in seconds.
DriverDepartureDate int64 `json:"driver_departure_Date"`
DriverDepartureAddress string `json:"driver_departure_Address,omitempty"`
Price Price `json:"price,omitempty"`
}
// AssertDriverJourneyRequired checks if the required fields are not zero-ed
func AssertDriverJourneyRequired(obj DriverJourney) error {
elements := map[string]interface{}{
"user": obj.User,
"driverDepartureDate": obj.DriverDepartureDate,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
if err := AssertUserRequired(obj.User); err != nil {
return err
}
if err := AssertCarRequired(obj.Car); err != nil {
return err
}
if err := AssertPriceRequired(obj.Price); err != nil {
return err
}
return nil
}
// AssertDriverJourneyConstraints checks if the values respects the defined constraints
func AssertDriverJourneyConstraints(obj DriverJourney) error {
return nil
}

View File

@ -0,0 +1,74 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type DriverPunctualAvailabilitiesRequest struct {
// The address or location description.
Address string `json:"address"`
// The latitude coordinate of the location.
Latitude float64 `json:"latitude"`
// The longitude coordinate of the location.
Longitude float64 `json:"longitude"`
// The radius around the location.
Radius int32 `json:"radius"`
Availabilities []PunctualAvailabilitySlot `json:"availabilities"`
User User `json:"user"`
Preferences Preferences `json:"preferences,omitempty"`
Car Car `json:"car,omitempty"`
}
// AssertDriverPunctualAvailabilitiesRequestRequired checks if the required fields are not zero-ed
func AssertDriverPunctualAvailabilitiesRequestRequired(obj DriverPunctualAvailabilitiesRequest) error {
elements := map[string]interface{}{
"address": obj.Address,
"latitude": obj.Latitude,
"longitude": obj.Longitude,
"radius": obj.Radius,
"availabilities": obj.Availabilities,
"user": obj.User,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
for _, el := range obj.Availabilities {
if err := AssertPunctualAvailabilitySlotRequired(el); err != nil {
return err
}
}
if err := AssertUserRequired(obj.User); err != nil {
return err
}
if err := AssertPreferencesRequired(obj.Preferences); err != nil {
return err
}
if err := AssertCarRequired(obj.Car); err != nil {
return err
}
return nil
}
// AssertDriverPunctualAvailabilitiesRequestConstraints checks if the values respects the defined constraints
func AssertDriverPunctualAvailabilitiesRequestConstraints(obj DriverPunctualAvailabilitiesRequest) error {
return nil
}

View File

@ -0,0 +1,74 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type DriverRegularAvailabilitiesRequest struct {
// The address or location description.
Address string `json:"address"`
// The latitude coordinate of the location.
Latitude float64 `json:"latitude"`
// The longitude coordinate of the location.
Longitude float64 `json:"longitude"`
// The radius around the location.
Radius int32 `json:"radius"`
Availabilities []RegularAvailabilitySlot `json:"availabilities"`
User User `json:"user"`
Preferences Preferences `json:"preferences,omitempty"`
Car Car `json:"car,omitempty"`
}
// AssertDriverRegularAvailabilitiesRequestRequired checks if the required fields are not zero-ed
func AssertDriverRegularAvailabilitiesRequestRequired(obj DriverRegularAvailabilitiesRequest) error {
elements := map[string]interface{}{
"address": obj.Address,
"latitude": obj.Latitude,
"longitude": obj.Longitude,
"radius": obj.Radius,
"availabilities": obj.Availabilities,
"user": obj.User,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
for _, el := range obj.Availabilities {
if err := AssertRegularAvailabilitySlotRequired(el); err != nil {
return err
}
}
if err := AssertUserRequired(obj.User); err != nil {
return err
}
if err := AssertPreferencesRequired(obj.Preferences); err != nil {
return err
}
if err := AssertCarRequired(obj.Car); err != nil {
return err
}
return nil
}
// AssertDriverRegularAvailabilitiesRequestConstraints checks if the values respects the defined constraints
func AssertDriverRegularAvailabilitiesRequestConstraints(obj DriverRegularAvailabilitiesRequest) error {
return nil
}

View File

@ -0,0 +1,45 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type DriverTrip struct {
User User `json:"user"`
Car Car `json:"car,omitempty"`
}
// AssertDriverTripRequired checks if the required fields are not zero-ed
func AssertDriverTripRequired(obj DriverTrip) error {
elements := map[string]interface{}{
"user": obj.User,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
if err := AssertUserRequired(obj.User); err != nil {
return err
}
if err := AssertCarRequired(obj.Car); err != nil {
return err
}
return nil
}
// AssertDriverTripConstraints checks if the values respects the defined constraints
func AssertDriverTripConstraints(obj DriverTrip) error {
return nil
}

View File

@ -0,0 +1,29 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type GetBookings404Response struct {
// Explain why the request couldn't be processed.
Error string `json:"error,omitempty"`
}
// AssertGetBookings404ResponseRequired checks if the required fields are not zero-ed
func AssertGetBookings404ResponseRequired(obj GetBookings404Response) error {
return nil
}
// AssertGetBookings404ResponseConstraints checks if the values respects the defined constraints
func AssertGetBookings404ResponseConstraints(obj GetBookings404Response) error {
return nil
}

View File

@ -0,0 +1,45 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type JourneySchedule struct {
// Passenger pickup datetime as a UNIX UTC timestamp in seconds.
PassengerPickupDate float32 `json:"passengerPickupDate"`
// Driver departure datetime as a UNIX UTC timestamp in seconds.
DriverDepartureDate float32 `json:"driverDepartureDate,omitempty"`
// Type of journey. A dynamic journey is happening in real time.
Type string `json:"type"`
}
// AssertJourneyScheduleRequired checks if the required fields are not zero-ed
func AssertJourneyScheduleRequired(obj JourneySchedule) error {
elements := map[string]interface{}{
"passengerPickupDate": obj.PassengerPickupDate,
"type": obj.Type,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
return nil
}
// AssertJourneyScheduleConstraints checks if the values respects the defined constraints
func AssertJourneyScheduleConstraints(obj JourneySchedule) error {
return nil
}

View File

@ -0,0 +1,67 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type PassengerTripRequest struct {
User User `json:"user"`
DestinationAddress string `json:"destination_address"`
DestinationLatitude float64 `json:"destination_latitude"`
DestinationLongitude float64 `json:"destination_longitude"`
DepartureAddress string `json:"departure_address"`
DepartureLatitude float64 `json:"departure_latitude"`
DepartureLongitude float64 `json:"departure_longitude"`
// Departure datetime using a UNIX UTC timestamp in seconds.
DepartureDate int32 `json:"departure_date"`
Preferences Preferences `json:"preferences,omitempty"`
}
// AssertPassengerTripRequestRequired checks if the required fields are not zero-ed
func AssertPassengerTripRequestRequired(obj PassengerTripRequest) error {
elements := map[string]interface{}{
"user": obj.User,
"destination_address": obj.DestinationAddress,
"destination_latitude": obj.DestinationLatitude,
"destination_longitude": obj.DestinationLongitude,
"departure_address": obj.DepartureAddress,
"departure_latitude": obj.DepartureLatitude,
"departure_longitude": obj.DepartureLongitude,
"departure_date": obj.DepartureDate,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
if err := AssertUserRequired(obj.User); err != nil {
return err
}
if err := AssertPreferencesRequired(obj.Preferences); err != nil {
return err
}
return nil
}
// AssertPassengerTripRequestConstraints checks if the values respects the defined constraints
func AssertPassengerTripRequestConstraints(obj PassengerTripRequest) error {
return nil
}

View File

@ -0,0 +1,63 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type PostConnectionsRequest struct {
From User `json:"from"`
To User `json:"to"`
// Free text content of a message. The message can contain all the details (phone number, email, etc.) allowing the recipient to call back the sender in order to carpool with him/her.
Message string `json:"message"`
// Defines if the recipient of this message is either the driver or the passenger.
RecipientCarpoolerType string `json:"recipientCarpoolerType"`
// ID of the Driver's journey to which the message is related (if any). Unique given the `Driver`'s `operator` property.
DriverJourneyId string `json:"driverJourneyId,omitempty"`
// ID of the Passenger's journey to which the message is related (if any). Unique given the `Passenger`'s `operator` property.
PassengerJourneyId string `json:"passengerJourneyId,omitempty"`
// Booking id is common between both operators, and must be created as a [UUID](https://datatracker.ietf.org/doc/html/rfc4122) by whoever initiates the booking. Usage of a [4 UUID](https://datatracker.ietf.org/doc/html/rfc4122#section-4.4) generation algorithm is advised.
BookingId string `json:"bookingId,omitempty"`
}
// AssertPostConnectionsRequestRequired checks if the required fields are not zero-ed
func AssertPostConnectionsRequestRequired(obj PostConnectionsRequest) error {
elements := map[string]interface{}{
"from": obj.From,
"to": obj.To,
"message": obj.Message,
"recipientCarpoolerType": obj.RecipientCarpoolerType,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
if err := AssertUserRequired(obj.From); err != nil {
return err
}
if err := AssertUserRequired(obj.To); err != nil {
return err
}
return nil
}
// AssertPostConnectionsRequestConstraints checks if the values respects the defined constraints
func AssertPostConnectionsRequestConstraints(obj PostConnectionsRequest) error {
return nil
}

View File

@ -0,0 +1,51 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"errors"
)
type Preferences struct {
// If driver journey, specifies if the driver allows smoking in the car.
Smoking bool `json:"smoking,omitempty"`
// If driver journey, specifies if the driver allows animals in the car.
Animals bool `json:"animals,omitempty"`
// If driver journey, specifies if the driver enjoys music in the car.
Music bool `json:"music,omitempty"`
// If driver journey, specifies if the driver enjoys talking with passengers.
IsTalker bool `json:"isTalker,omitempty"`
// If driver journey, specifies the size of allowed luggages. From very small (1) to very big (5).
LuggageSize int32 `json:"luggageSize,omitempty"`
}
// AssertPreferencesRequired checks if the required fields are not zero-ed
func AssertPreferencesRequired(obj Preferences) error {
return nil
}
// AssertPreferencesConstraints checks if the values respects the defined constraints
func AssertPreferencesConstraints(obj Preferences) error {
if obj.LuggageSize < 1 {
return &ParsingError{Err: errors.New(errMsgMinValueConstraint)}
}
if obj.LuggageSize > 5 {
return &ParsingError{Err: errors.New(errMsgMaxValueConstraint)}
}
return nil
}

View File

@ -0,0 +1,35 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type Price struct {
// Either « FREE », « PAYING » or « UNKNOWN ». « UNKNOWN » is given when it should be « PAYING » but we cannot set the price yet.
Type string `json:"type,omitempty"`
// Carpooling passenger cost estimate. In the case of integrated booking by API, amount expected by the carpooling operator.
Amount float32 `json:"amount,omitempty"`
// ISO 4217 code representing the currency of the price.
Currency string `json:"currency,omitempty"`
}
// AssertPriceRequired checks if the required fields are not zero-ed
func AssertPriceRequired(obj Price) error {
return nil
}
// AssertPriceConstraints checks if the values respects the defined constraints
func AssertPriceConstraints(obj Price) error {
return nil
}

View File

@ -0,0 +1,46 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type PunctualAvailabilitySlot struct {
// UNIX UTC timestamp in seconds.
Date int32 `json:"date"`
// Start time for punctual scheduling (RFC3339 partial-time).
StartTime string `json:"startTime"`
// End time for punctual scheduling (RFC3339 partial-time).
EndTime string `json:"endTime"`
}
// AssertPunctualAvailabilitySlotRequired checks if the required fields are not zero-ed
func AssertPunctualAvailabilitySlotRequired(obj PunctualAvailabilitySlot) error {
elements := map[string]interface{}{
"date": obj.Date,
"startTime": obj.StartTime,
"endTime": obj.EndTime,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
return nil
}
// AssertPunctualAvailabilitySlotConstraints checks if the values respects the defined constraints
func AssertPunctualAvailabilitySlotConstraints(obj PunctualAvailabilitySlot) error {
return nil
}

View File

@ -0,0 +1,46 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
type RegularAvailabilitySlot struct {
// Day of the week for regular scheduling.
DayOfWeek string `json:"dayOfWeek"`
// Start time for regular scheduling (RFC3339 partial-time).
StartTime string `json:"startTime"`
// End time for regular scheduling (RFC3339 partial-time).
EndTime string `json:"endTime"`
}
// AssertRegularAvailabilitySlotRequired checks if the required fields are not zero-ed
func AssertRegularAvailabilitySlotRequired(obj RegularAvailabilitySlot) error {
elements := map[string]interface{}{
"dayOfWeek": obj.DayOfWeek,
"startTime": obj.StartTime,
"endTime": obj.EndTime,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
return nil
}
// AssertRegularAvailabilitySlotConstraints checks if the values respects the defined constraints
func AssertRegularAvailabilitySlotConstraints(obj RegularAvailabilitySlot) error {
return nil
}

View File

@ -0,0 +1,74 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"errors"
)
type User struct {
// User's identifier. It MUST be unique for a given `operator`.
Id string `json:"id"`
// The operator identifier. MUST be a Fully Qualified Domain Name (example carpool.mycity.com) owned by the operator or a Partially Qualified Domain Name (example operator.org) owned and exclusively operated by the operator. Operators SHOULD always send the same value.
Operator string `json:"operator"`
// User's alias.
Alias string `json:"alias"`
// User's first name.
FirstName string `json:"firstName,omitempty"`
// User's last name.
LastName string `json:"lastName,omitempty"`
// User's grade from 1 to 5.
Grade int32 `json:"grade,omitempty"`
// User's profile picture absolute URL.
Picture string `json:"picture,omitempty"`
// User's gender. 'O' stands for 'Other'.
Gender string `json:"gender,omitempty"`
// true if the identity of this user has been verified by the operator or a third party; and the firstName, lastName, birthdate have been confirmed as identitical to an official identity proof document. Can be left empty if the information is not available.
VerifiedIdentity bool `json:"verifiedIdentity,omitempty"`
}
// AssertUserRequired checks if the required fields are not zero-ed
func AssertUserRequired(obj User) error {
elements := map[string]interface{}{
"id": obj.Id,
"operator": obj.Operator,
"alias": obj.Alias,
}
for name, el := range elements {
if isZero := IsZeroValue(el); isZero {
return &RequiredError{Field: name}
}
}
return nil
}
// AssertUserConstraints checks if the values respects the defined constraints
func AssertUserConstraints(obj User) error {
if obj.Grade < 1 {
return &ParsingError{Err: errors.New(errMsgMinValueConstraint)}
}
if obj.Grade > 5 {
return &ParsingError{Err: errors.New(errMsgMaxValueConstraint)}
}
return nil
}

View File

@ -0,0 +1,68 @@
package openapi
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"strings"
)
func CheckOperatorAuthorization(r *http.Request, authorizedOperators map[string]string) bool {
authorizationHeader := r.Header.Get("Authorization")
if authorizationHeader == "" {
return false
}
parts := strings.Split(authorizationHeader, " ")
if len(parts) != 2 {
return false
}
if parts[0] != "Bearer" {
return false
}
apiKey := parts[1]
operatorName, authorized := authorizedOperators[apiKey]
var operator string
var found bool
if r.Body != nil {
body, err := ioutil.ReadAll(r.Body)
if err == nil {
var payload map[string]interface{}
if json.Unmarshal(body, &payload) == nil {
// Check for "operator" in the top-level body
if op, ok := payload["operator"].(string); ok {
operator = op
found = true
} else {
// Check for "user" struct in the body
if user, ok := payload["user"].(map[string]interface{}); ok {
if op, ok := user["operator"].(string); ok {
operator = op
found = true
}
}
}
}
}
r.Body = ioutil.NopCloser(bytes.NewReader(body))
}
// If operator is not found in the request body, check the request parameters.
if !found {
operatorFromParams := r.URL.Query().Get("operator")
if operatorFromParams != "" {
operator = operatorFromParams
found = true
}
}
if found && operator == operatorName && authorized {
return true
}
return false
}
var AuthorizedOperators = map[string]string{
"$2y$10$TJuDZDu.mqy5dDKGMSfxSO5f6pz/36XVrAyQ1CXJd63ccjRlX7lmK": "test.com",
}

View File

@ -0,0 +1,297 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"encoding/json"
"errors"
"github.com/gorilla/mux"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"strconv"
"strings"
)
// A Route defines the parameters for an api endpoint
type Route struct {
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
// Routes is a map of defined api endpoints
type Routes map[string]Route
// Router defines the required methods for retrieving api routes
type Router interface {
Routes() Routes
}
const errMsgRequiredMissing = "required parameter is missing"
const errMsgMinValueConstraint = "provided parameter is not respecting minimum value constraint"
const errMsgMaxValueConstraint = "provided parameter is not respecting maximum value constraint"
// NewRouter creates a new router for any number of api routers
func NewRouter(routers ...Router) *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, api := range routers {
for name, route := range api.Routes() {
var handler http.Handler
handler = route.HandlerFunc
handler = Logger(handler, name)
router.
Methods(route.Method).
Path(route.Pattern).
Name(name).
Handler(handler)
}
}
return router
}
// EncodeJSONResponse uses the json encoder to write an interface to the http response with an optional status code
func EncodeJSONResponse(i interface{}, status *int, w http.ResponseWriter) error {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
if status != nil {
w.WriteHeader(*status)
} else {
w.WriteHeader(http.StatusOK)
}
if i != nil {
return json.NewEncoder(w).Encode(i)
}
return nil
}
// ReadFormFileToTempFile reads file data from a request form and writes it to a temporary file
func ReadFormFileToTempFile(r *http.Request, key string) (*os.File, error) {
_, fileHeader, err := r.FormFile(key)
if err != nil {
return nil, err
}
return readFileHeaderToTempFile(fileHeader)
}
// ReadFormFilesToTempFiles reads files array data from a request form and writes it to a temporary files
func ReadFormFilesToTempFiles(r *http.Request, key string) ([]*os.File, error) {
if err := r.ParseMultipartForm(32 << 20); err != nil {
return nil, err
}
files := make([]*os.File, 0, len(r.MultipartForm.File[key]))
for _, fileHeader := range r.MultipartForm.File[key] {
file, err := readFileHeaderToTempFile(fileHeader)
if err != nil {
return nil, err
}
files = append(files, file)
}
return files, nil
}
// readFileHeaderToTempFile reads multipart.FileHeader and writes it to a temporary file
func readFileHeaderToTempFile(fileHeader *multipart.FileHeader) (*os.File, error) {
formFile, err := fileHeader.Open()
if err != nil {
return nil, err
}
defer formFile.Close()
fileBytes, err := ioutil.ReadAll(formFile)
if err != nil {
return nil, err
}
file, err := ioutil.TempFile("", fileHeader.Filename)
if err != nil {
return nil, err
}
defer file.Close()
file.Write(fileBytes)
return file, nil
}
type Number interface {
~int32 | ~int64 | ~float32 | ~float64
}
type ParseString[T Number | string | bool] func(v string) (T, error)
// parseFloat64 parses a string parameter to an float64.
func parseFloat64(param string) (float64, error) {
if param == "" {
return 0, nil
}
return strconv.ParseFloat(param, 64)
}
// parseFloat32 parses a string parameter to an float32.
func parseFloat32(param string) (float32, error) {
if param == "" {
return 0, nil
}
v, err := strconv.ParseFloat(param, 32)
return float32(v), err
}
// parseInt64 parses a string parameter to an int64.
func parseInt64(param string) (int64, error) {
if param == "" {
return 0, nil
}
return strconv.ParseInt(param, 10, 64)
}
// parseInt32 parses a string parameter to an int32.
func parseInt32(param string) (int32, error) {
if param == "" {
return 0, nil
}
val, err := strconv.ParseInt(param, 10, 32)
return int32(val), err
}
// parseBool parses a string parameter to an bool.
func parseBool(param string) (bool, error) {
if param == "" {
return false, nil
}
return strconv.ParseBool(param)
}
type Operation[T Number | string | bool] func(actual string) (T, bool, error)
func WithRequire[T Number | string | bool](parse ParseString[T]) Operation[T] {
var empty T
return func(actual string) (T, bool, error) {
if actual == "" {
return empty, false, errors.New(errMsgRequiredMissing)
}
v, err := parse(actual)
return v, false, err
}
}
func WithDefaultOrParse[T Number | string | bool](def T, parse ParseString[T]) Operation[T] {
return func(actual string) (T, bool, error) {
if actual == "" {
return def, true, nil
}
v, err := parse(actual)
return v, false, err
}
}
func WithParse[T Number | string | bool](parse ParseString[T]) Operation[T] {
return func(actual string) (T, bool, error) {
v, err := parse(actual)
return v, false, err
}
}
type Constraint[T Number | string | bool] func(actual T) error
func WithMinimum[T Number](expected T) Constraint[T] {
return func(actual T) error {
if actual < expected {
return errors.New(errMsgMinValueConstraint)
}
return nil
}
}
func WithMaximum[T Number](expected T) Constraint[T] {
return func(actual T) error {
if actual > expected {
return errors.New(errMsgMaxValueConstraint)
}
return nil
}
}
// parseNumericParameter parses a numeric parameter to its respective type.
func parseNumericParameter[T Number](param string, fn Operation[T], checks ...Constraint[T]) (T, error) {
v, ok, err := fn(param)
if err != nil {
return 0, err
}
if !ok {
for _, check := range checks {
if err := check(v); err != nil {
return 0, err
}
}
}
return v, nil
}
// parseBoolParameter parses a string parameter to a bool
func parseBoolParameter(param string, fn Operation[bool]) (bool, error) {
v, _, err := fn(param)
return v, err
}
// parseNumericArrayParameter parses a string parameter containing array of values to its respective type.
func parseNumericArrayParameter[T Number](param, delim string, required bool, fn Operation[T], checks ...Constraint[T]) ([]T, error) {
if param == "" {
if required {
return nil, errors.New(errMsgRequiredMissing)
}
return nil, nil
}
str := strings.Split(param, delim)
values := make([]T, len(str))
for i, s := range str {
v, ok, err := fn(s)
if err != nil {
return nil, err
}
if !ok {
for _, check := range checks {
if err := check(v); err != nil {
return nil, err
}
}
}
values[i] = v
}
return values, nil
}

View File

@ -0,0 +1,40 @@
/*
* Solidarity Mobility API
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 1.0.0
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package Solidarity_api
import (
"github.com/spf13/viper"
"log"
"net/http"
"solidarity-service/handler"
"solidarity-service/interoperability/solidarity-api/server/openapi"
"solidarity-service/storage"
)
func Run(cfg *viper.Viper, handler *handler.SolidarityServiceHandler, storage storage.Storage) {
BookingsFilterAPIService := openapi.NewBookingsFilterAPIService(cfg, handler, storage)
BookingsFilterAPIController := openapi.NewBookingsFilterAPIController(BookingsFilterAPIService)
DriverAvailabilityAndScheduleAPIService := openapi.NewDriverAvailabilityAndScheduleAPIService(cfg, handler, storage)
DriverAvailabilityAndScheduleAPIController := openapi.NewDriverAvailabilityAndScheduleAPIController(DriverAvailabilityAndScheduleAPIService)
InteractAPIService := openapi.NewInteractAPIService(cfg, handler, storage)
InteractAPIController := openapi.NewInteractAPIController(InteractAPIService)
PassengerTripRequestAPIService := openapi.NewPassengerTripRequestAPIService(cfg, handler, storage)
PassengerTripRequestAPIController := openapi.NewPassengerTripRequestAPIController(PassengerTripRequestAPIService)
SearchAPIService := openapi.NewSearchAPIService(cfg, handler, storage)
SearchAPIController := openapi.NewSearchAPIController(SearchAPIService)
router := openapi.NewRouter(BookingsFilterAPIController, DriverAvailabilityAndScheduleAPIController, InteractAPIController, PassengerTripRequestAPIController, SearchAPIController)
log.Fatal(http.ListenAndServe(":9999", router))
}

60
main.go Normal file
View File

@ -0,0 +1,60 @@
package main
import (
routing "git.coopgo.io/coopgo-platform/routing-service"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
SolidarityServiceHandler "solidarity-service/handler"
api "solidarity-service/interoperability/solidarity-api/server"
grpcserver "solidarity-service/servers/grpc/server"
"solidarity-service/storage"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
cfg, err := ReadConfig()
if err != nil {
panic(err)
}
var (
service_name = cfg.GetString("name")
grpc_enable = cfg.GetBool("services.grpc.enable")
solidarity_api_enable = cfg.GetBool("services.solidarity-api.enable")
routing_service_type = cfg.GetString("routing.type")
valhalla_base_url = cfg.GetString("routing.valhalla.base_url")
)
log.Info().Msg("Running " + service_name)
storageService, err := storage.NewStorage(cfg)
if err != nil {
log.Fatal().Err(err).Msg("Could not initiate the storage service")
return
}
routing, err := routing.NewRoutingService(routing_service_type, valhalla_base_url)
if err != nil {
log.Fatal().Err(err).Msg("Could not initiate the routing service")
return
}
handler, err := SolidarityServiceHandler.NewSolidarityServiceHandler(cfg, routing, storageService)
if err != nil {
log.Fatal().Err(err).Msg("Could not initiate the solidarity service handler")
return
}
failed := make(chan error)
if grpc_enable {
log.Info().Msg("Running gRPC server")
go grpcserver.Run(failed, cfg, handler)
}
if solidarity_api_enable {
log.Info().Msg("Running OCSS REST API")
go api.Run(cfg, handler, storageService)
}
err = <-failed
log.Fatal().Err(err).Msg("Terminating")
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,133 @@
syntax = "proto3";
option go_package = "git.coopgo.io/coopgo-platform/solidarity-service/servers/grpc/proto";
import "google/protobuf/timestamp.proto";
message Feature {
double lat = 1;
double long = 2;
string address = 3;
}
message DriverJourney {
User user = 1;
optional Car car = 2;
google.protobuf.Timestamp driver_departure_Date = 3;
optional Price price = 4;
string driver_departure_Address = 5;
oneof availabilities {
RepeatedPunctualAvailabilitySlot repeated_punctual_availabilities = 6;
RepeatedRegularAvailabilitySlot repeated_regular_availabilities = 7;
}
}
message RepeatedPunctualAvailabilitySlot {
repeated PunctualAvailabilitySlot punctual_availabilities = 1;
}
message RepeatedRegularAvailabilitySlot {
repeated RegularAvailabilitySlot regular_availabilities = 1;
}
message DriverRequest{
Feature driver_address = 1;
int32 driver_radius = 2;
User driver = 3;
optional Preferences preferences = 4;
optional Car car = 5;
}
message PunctualAvailabilitySlot {
google.protobuf.Timestamp date = 1;
string startTime = 2;
string endTime = 3;
}
message RegularAvailabilitySlot {
DayOfWeek dayOfWeek = 1;
string startTime = 2;
string endTime = 3;
}
enum DayOfWeek {
MON = 0;
TUE = 1;
WED = 3;
THU = 4;
FRI = 5;
SAT = 6;
SUN = 7;
}
message BookingRequest {
string id = 1;
string passengerId = 2;
string driverId = 3;
BookingStatus status = 4;
}
message Booking {
string id = 1;
User driver = 2;
User passenger = 3;
google.protobuf.Timestamp passengerPickupDate =4;
Feature passenger_departure_route = 5;
Feature passenger_destination_route = 6;
BookingStatus status = 7;
optional int64 duration = 8;
optional int64 distance = 9;
Price price = 10;
optional Car car = 11;
}
message Car {
optional string model = 1;
optional string brand = 2;
}
message Preferences {
optional bool smoking = 1;
optional bool animals = 2;
optional bool music = 3;
optional bool is_talker = 4;
optional int64 luggage_size = 5;
}
enum PriceType {
FREE = 0;
PAYING = 1;
UNKNOWN = 2;
}
message Price {
optional PriceType type = 1;
optional double amount = 2;
optional string currency = 3;
}
message User {
string id = 1;
string alias = 2;
optional string first_name = 3;
optional string last_name = 4;
optional int64 grade = 5;
optional string picture = 6;
optional string gender = 7;
optional bool verified_identity = 8;
}
enum BookingStatus {
INITIATED = 0;
WAITING_DRIVER_CONFIRMATION = 1;
WAITING_PASSENGER_CONFIRMATION = 2;
CONFIRMED = 3;
CANCELLED = 4;
COMPLETED_PENDING_VALIDATION = 5;
VALIDATED = 6;
}
enum UserType{
driver = 0;
passenger = 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
syntax = "proto3";
option go_package = "git.coopgo.io/coopgo-platform/solidarity-service/servers/grpc/proto";
import "google/protobuf/timestamp.proto";
import "solidarity-api-types.proto";
service SolidarityService {
rpc SetDriverRegularAvailabilities(DriverRegularAvailabilities) returns (DriverAvailabilitiesResponse) {}
rpc SetDriverPunctualAvailabilities(DriverPunctualAvailabilities) returns (DriverAvailabilitiesResponse) {}
rpc CreateBooking(CreateBookingRequest) returns (CreateBookingResponse) {}
rpc UpdateBooking(UpdateBookingRequest) returns (UpdateBookingResponse) {}
rpc GetBooking(GetBookingRequest) returns (GetBookingResponse) {}
rpc GetBookingsByStatus(GetBookingsByStatusRequest) returns (GetBookingsByStatusResponse) {}
rpc DriverJourneys(DriverJourneysRequest) returns (DriverJourneysResponse) {}
rpc SetPassengerTrip(PassengerTripRequest) returns (PassengerTripResponse) {}
}
message PassengerTripRequest{
Feature passenger_departure_address = 1;
Feature passenger_destination_address = 2;
google.protobuf.Timestamp passenger_pickup_date = 3;
User passenger = 4;
optional Preferences preferences = 5;
}
message DriverRegularAvailabilities{
DriverRequest driver_request = 1;
repeated RegularAvailabilitySlot driver_availabilities = 2;
}
message DriverPunctualAvailabilities{
DriverRequest driver_request = 1;
repeated PunctualAvailabilitySlot driver_availabilities = 2;
}
message PassengerTripResponse {
bool success = 1;
optional string message = 2;
}
message DriverAvailabilitiesResponse {
bool success = 1;
optional string message = 2;
}
message CreateBookingRequest {
BookingRequest booking = 1;
}
message CreateBookingResponse {
Booking booking = 1;
}
message UpdateBookingRequest {
string booking_id = 1;
BookingStatus status = 2;
optional string message = 3;
}
message UpdateBookingResponse {
bool success = 1;
optional string message = 2;
}
message GetBookingRequest {
string booking_id = 1;
}
message GetBookingResponse {
Booking booking = 1;
}
message GetBookingsByStatusRequest{
BookingStatus status = 1;
UserType type = 2;
string user_id = 3;
}
message DriverJourneysRequest {
Feature departure = 1;
google.protobuf.Timestamp departure_date = 2;
}
message DriverJourneysResponse {
repeated DriverJourney driver_journeys = 1;
}
message GetBookingsByStatusResponse{
repeated Booking booking = 1;
}

View File

@ -0,0 +1,368 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc v3.12.4
// source: solidarity-api.proto
package proto
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
const (
SolidarityService_SetDriverRegularAvailabilities_FullMethodName = "/SolidarityService/SetDriverRegularAvailabilities"
SolidarityService_SetDriverPunctualAvailabilities_FullMethodName = "/SolidarityService/SetDriverPunctualAvailabilities"
SolidarityService_CreateBooking_FullMethodName = "/SolidarityService/CreateBooking"
SolidarityService_UpdateBooking_FullMethodName = "/SolidarityService/UpdateBooking"
SolidarityService_GetBooking_FullMethodName = "/SolidarityService/GetBooking"
SolidarityService_GetBookingsByStatus_FullMethodName = "/SolidarityService/GetBookingsByStatus"
SolidarityService_DriverJourneys_FullMethodName = "/SolidarityService/DriverJourneys"
SolidarityService_SetPassengerTrip_FullMethodName = "/SolidarityService/SetPassengerTrip"
)
// SolidarityServiceClient is the client API for SolidarityService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type SolidarityServiceClient interface {
SetDriverRegularAvailabilities(ctx context.Context, in *DriverRegularAvailabilities, opts ...grpc.CallOption) (*DriverAvailabilitiesResponse, error)
SetDriverPunctualAvailabilities(ctx context.Context, in *DriverPunctualAvailabilities, opts ...grpc.CallOption) (*DriverAvailabilitiesResponse, error)
CreateBooking(ctx context.Context, in *CreateBookingRequest, opts ...grpc.CallOption) (*CreateBookingResponse, error)
UpdateBooking(ctx context.Context, in *UpdateBookingRequest, opts ...grpc.CallOption) (*UpdateBookingResponse, error)
GetBooking(ctx context.Context, in *GetBookingRequest, opts ...grpc.CallOption) (*GetBookingResponse, error)
GetBookingsByStatus(ctx context.Context, in *GetBookingsByStatusRequest, opts ...grpc.CallOption) (*GetBookingsByStatusResponse, error)
DriverJourneys(ctx context.Context, in *DriverJourneysRequest, opts ...grpc.CallOption) (*DriverJourneysResponse, error)
SetPassengerTrip(ctx context.Context, in *PassengerTripRequest, opts ...grpc.CallOption) (*PassengerTripResponse, error)
}
type solidarityServiceClient struct {
cc grpc.ClientConnInterface
}
func NewSolidarityServiceClient(cc grpc.ClientConnInterface) SolidarityServiceClient {
return &solidarityServiceClient{cc}
}
func (c *solidarityServiceClient) SetDriverRegularAvailabilities(ctx context.Context, in *DriverRegularAvailabilities, opts ...grpc.CallOption) (*DriverAvailabilitiesResponse, error) {
out := new(DriverAvailabilitiesResponse)
err := c.cc.Invoke(ctx, SolidarityService_SetDriverRegularAvailabilities_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *solidarityServiceClient) SetDriverPunctualAvailabilities(ctx context.Context, in *DriverPunctualAvailabilities, opts ...grpc.CallOption) (*DriverAvailabilitiesResponse, error) {
out := new(DriverAvailabilitiesResponse)
err := c.cc.Invoke(ctx, SolidarityService_SetDriverPunctualAvailabilities_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *solidarityServiceClient) CreateBooking(ctx context.Context, in *CreateBookingRequest, opts ...grpc.CallOption) (*CreateBookingResponse, error) {
out := new(CreateBookingResponse)
err := c.cc.Invoke(ctx, SolidarityService_CreateBooking_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *solidarityServiceClient) UpdateBooking(ctx context.Context, in *UpdateBookingRequest, opts ...grpc.CallOption) (*UpdateBookingResponse, error) {
out := new(UpdateBookingResponse)
err := c.cc.Invoke(ctx, SolidarityService_UpdateBooking_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *solidarityServiceClient) GetBooking(ctx context.Context, in *GetBookingRequest, opts ...grpc.CallOption) (*GetBookingResponse, error) {
out := new(GetBookingResponse)
err := c.cc.Invoke(ctx, SolidarityService_GetBooking_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *solidarityServiceClient) GetBookingsByStatus(ctx context.Context, in *GetBookingsByStatusRequest, opts ...grpc.CallOption) (*GetBookingsByStatusResponse, error) {
out := new(GetBookingsByStatusResponse)
err := c.cc.Invoke(ctx, SolidarityService_GetBookingsByStatus_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *solidarityServiceClient) DriverJourneys(ctx context.Context, in *DriverJourneysRequest, opts ...grpc.CallOption) (*DriverJourneysResponse, error) {
out := new(DriverJourneysResponse)
err := c.cc.Invoke(ctx, SolidarityService_DriverJourneys_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *solidarityServiceClient) SetPassengerTrip(ctx context.Context, in *PassengerTripRequest, opts ...grpc.CallOption) (*PassengerTripResponse, error) {
out := new(PassengerTripResponse)
err := c.cc.Invoke(ctx, SolidarityService_SetPassengerTrip_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// SolidarityServiceServer is the server API for SolidarityService service.
// All implementations must embed UnimplementedSolidarityServiceServer
// for forward compatibility
type SolidarityServiceServer interface {
SetDriverRegularAvailabilities(context.Context, *DriverRegularAvailabilities) (*DriverAvailabilitiesResponse, error)
SetDriverPunctualAvailabilities(context.Context, *DriverPunctualAvailabilities) (*DriverAvailabilitiesResponse, error)
CreateBooking(context.Context, *CreateBookingRequest) (*CreateBookingResponse, error)
UpdateBooking(context.Context, *UpdateBookingRequest) (*UpdateBookingResponse, error)
GetBooking(context.Context, *GetBookingRequest) (*GetBookingResponse, error)
GetBookingsByStatus(context.Context, *GetBookingsByStatusRequest) (*GetBookingsByStatusResponse, error)
DriverJourneys(context.Context, *DriverJourneysRequest) (*DriverJourneysResponse, error)
SetPassengerTrip(context.Context, *PassengerTripRequest) (*PassengerTripResponse, error)
mustEmbedUnimplementedSolidarityServiceServer()
}
// UnimplementedSolidarityServiceServer must be embedded to have forward compatible implementations.
type UnimplementedSolidarityServiceServer struct {
}
func (UnimplementedSolidarityServiceServer) SetDriverRegularAvailabilities(context.Context, *DriverRegularAvailabilities) (*DriverAvailabilitiesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SetDriverRegularAvailabilities not implemented")
}
func (UnimplementedSolidarityServiceServer) SetDriverPunctualAvailabilities(context.Context, *DriverPunctualAvailabilities) (*DriverAvailabilitiesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SetDriverPunctualAvailabilities not implemented")
}
func (UnimplementedSolidarityServiceServer) CreateBooking(context.Context, *CreateBookingRequest) (*CreateBookingResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateBooking not implemented")
}
func (UnimplementedSolidarityServiceServer) UpdateBooking(context.Context, *UpdateBookingRequest) (*UpdateBookingResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateBooking not implemented")
}
func (UnimplementedSolidarityServiceServer) GetBooking(context.Context, *GetBookingRequest) (*GetBookingResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBooking not implemented")
}
func (UnimplementedSolidarityServiceServer) GetBookingsByStatus(context.Context, *GetBookingsByStatusRequest) (*GetBookingsByStatusResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBookingsByStatus not implemented")
}
func (UnimplementedSolidarityServiceServer) DriverJourneys(context.Context, *DriverJourneysRequest) (*DriverJourneysResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DriverJourneys not implemented")
}
func (UnimplementedSolidarityServiceServer) SetPassengerTrip(context.Context, *PassengerTripRequest) (*PassengerTripResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SetPassengerTrip not implemented")
}
func (UnimplementedSolidarityServiceServer) mustEmbedUnimplementedSolidarityServiceServer() {}
// UnsafeSolidarityServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to SolidarityServiceServer will
// result in compilation errors.
type UnsafeSolidarityServiceServer interface {
mustEmbedUnimplementedSolidarityServiceServer()
}
func RegisterSolidarityServiceServer(s grpc.ServiceRegistrar, srv SolidarityServiceServer) {
s.RegisterService(&SolidarityService_ServiceDesc, srv)
}
func _SolidarityService_SetDriverRegularAvailabilities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DriverRegularAvailabilities)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SolidarityServiceServer).SetDriverRegularAvailabilities(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SolidarityService_SetDriverRegularAvailabilities_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SolidarityServiceServer).SetDriverRegularAvailabilities(ctx, req.(*DriverRegularAvailabilities))
}
return interceptor(ctx, in, info, handler)
}
func _SolidarityService_SetDriverPunctualAvailabilities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DriverPunctualAvailabilities)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SolidarityServiceServer).SetDriverPunctualAvailabilities(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SolidarityService_SetDriverPunctualAvailabilities_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SolidarityServiceServer).SetDriverPunctualAvailabilities(ctx, req.(*DriverPunctualAvailabilities))
}
return interceptor(ctx, in, info, handler)
}
func _SolidarityService_CreateBooking_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateBookingRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SolidarityServiceServer).CreateBooking(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SolidarityService_CreateBooking_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SolidarityServiceServer).CreateBooking(ctx, req.(*CreateBookingRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SolidarityService_UpdateBooking_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateBookingRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SolidarityServiceServer).UpdateBooking(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SolidarityService_UpdateBooking_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SolidarityServiceServer).UpdateBooking(ctx, req.(*UpdateBookingRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SolidarityService_GetBooking_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBookingRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SolidarityServiceServer).GetBooking(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SolidarityService_GetBooking_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SolidarityServiceServer).GetBooking(ctx, req.(*GetBookingRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SolidarityService_GetBookingsByStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBookingsByStatusRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SolidarityServiceServer).GetBookingsByStatus(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SolidarityService_GetBookingsByStatus_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SolidarityServiceServer).GetBookingsByStatus(ctx, req.(*GetBookingsByStatusRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SolidarityService_DriverJourneys_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DriverJourneysRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SolidarityServiceServer).DriverJourneys(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SolidarityService_DriverJourneys_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SolidarityServiceServer).DriverJourneys(ctx, req.(*DriverJourneysRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SolidarityService_SetPassengerTrip_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PassengerTripRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SolidarityServiceServer).SetPassengerTrip(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SolidarityService_SetPassengerTrip_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SolidarityServiceServer).SetPassengerTrip(ctx, req.(*PassengerTripRequest))
}
return interceptor(ctx, in, info, handler)
}
// SolidarityService_ServiceDesc is the grpc.ServiceDesc for SolidarityService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var SolidarityService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "SolidarityService",
HandlerType: (*SolidarityServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "SetDriverRegularAvailabilities",
Handler: _SolidarityService_SetDriverRegularAvailabilities_Handler,
},
{
MethodName: "SetDriverPunctualAvailabilities",
Handler: _SolidarityService_SetDriverPunctualAvailabilities_Handler,
},
{
MethodName: "CreateBooking",
Handler: _SolidarityService_CreateBooking_Handler,
},
{
MethodName: "UpdateBooking",
Handler: _SolidarityService_UpdateBooking_Handler,
},
{
MethodName: "GetBooking",
Handler: _SolidarityService_GetBooking_Handler,
},
{
MethodName: "GetBookingsByStatus",
Handler: _SolidarityService_GetBookingsByStatus_Handler,
},
{
MethodName: "DriverJourneys",
Handler: _SolidarityService_DriverJourneys_Handler,
},
{
MethodName: "SetPassengerTrip",
Handler: _SolidarityService_SetPassengerTrip_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "solidarity-api.proto",
}

View File

@ -0,0 +1,27 @@
package grpcserver
import (
"solidarity-service/internal"
"solidarity-service/servers/grpc/proto"
)
func ConvertInternalToProtoBookingStatus(internalStatus internal.BookingStatus) proto.BookingStatus {
switch internalStatus {
case internal.BookingStatusINITIATED:
return proto.BookingStatus_INITIATED
case internal.BookingStatusWAITINGPASSENGERCONFIRMATION:
return proto.BookingStatus_WAITING_PASSENGER_CONFIRMATION
case internal.BookingStatusWAITINGDRIVERCONFIRMATION:
return proto.BookingStatus_WAITING_DRIVER_CONFIRMATION
case internal.BookingStatusCONFIRMED:
return proto.BookingStatus_CONFIRMED
case internal.BookingStatusCANCELLED:
return proto.BookingStatus_CANCELLED
case internal.BookingStatusCOMPLETEDPENDINGVALIDATION:
return proto.BookingStatus_COMPLETED_PENDING_VALIDATION
case internal.BookingStatusVALIDATED:
return proto.BookingStatus_VALIDATED
default:
return proto.BookingStatus_CONFIRMED
}
}

View File

@ -0,0 +1,26 @@
package grpcserver
import (
"solidarity-service/servers/grpc/proto"
)
func ConvertToProtoDayOfTheWeek(day string) proto.DayOfWeek {
switch day {
case "MON":
return proto.DayOfWeek_MON
case "TUE":
return proto.DayOfWeek_TUE
case "WED":
return proto.DayOfWeek_WED
case "THU":
return proto.DayOfWeek_THU
case "FRI":
return proto.DayOfWeek_FRI
case "SAT":
return proto.DayOfWeek_FRI
case "SUN":
return proto.DayOfWeek_SAT
default:
return proto.DayOfWeek_MON
}
}

View File

@ -0,0 +1,40 @@
package grpcserver
import (
"fmt"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
"google.golang.org/grpc"
"net"
"solidarity-service/handler"
"solidarity-service/servers/grpc/proto"
)
type SolidarityServiceServerImpl struct {
Handler *handler.SolidarityServiceHandler
proto.UnimplementedSolidarityServiceServer
}
func NewSolidarityServiceServer(handler *handler.SolidarityServiceHandler) *SolidarityServiceServerImpl {
return &SolidarityServiceServerImpl{
Handler: handler,
}
}
func Run(done chan error, cfg *viper.Viper, handler *handler.SolidarityServiceHandler) {
var (
address = ":" + cfg.GetString("services.grpc.port")
)
server := grpc.NewServer()
proto.RegisterSolidarityServiceServer(server, NewSolidarityServiceServer(handler))
l, err := net.Listen("tcp", address)
if err != nil {
log.Fatal().Err(err)
return
}
if err := server.Serve(l); err != nil {
fmt.Println("gRPC service ended")
done <- err
}
}

View File

@ -0,0 +1,543 @@
package grpcserver
import (
"context"
"errors"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"
"solidarity-service/internal"
"solidarity-service/servers/grpc/proto"
)
func (s *SolidarityServiceServerImpl) SetDriverRegularAvailabilities(ctx context.Context, req *proto.DriverRegularAvailabilities) (resp *proto.DriverAvailabilitiesResponse, err error) {
if req.DriverRequest.Driver.Id == "" || req.DriverRequest.Driver.Alias == "" || req.DriverAvailabilities == nil || req.DriverRequest.DriverAddress == nil || req.DriverRequest.DriverRadius == 0 {
return &proto.DriverAvailabilitiesResponse{
Success: false,
}, errors.New("missing required fields")
}
driver := internal.Driver{
Driver_departure_address: &geojson.Feature{
Type: "Feature",
Geometry: orb.Geometry(orb.Point{req.DriverRequest.DriverAddress.Lat, req.DriverRequest.DriverAddress.Long}),
Properties: geojson.Properties{
"name": req.DriverRequest.DriverAddress.Address,
},
},
Radius: req.DriverRequest.DriverRadius,
Driver: internal.User{
ID: req.DriverRequest.Driver.Id,
Alias: req.DriverRequest.Driver.Alias,
},
AvailabilitiesType: internal.Regular,
}
if req.DriverRequest.Driver.FirstName != nil {
driver.Driver.FirstName = *req.DriverRequest.Driver.FirstName
}
if req.DriverRequest.Driver.LastName != nil {
driver.Driver.LastName = *req.DriverRequest.Driver.LastName
}
if req.DriverRequest.Driver.Grade != nil {
driver.Driver.Grade = *req.DriverRequest.Driver.Grade
}
if req.DriverRequest.Driver.Picture != nil {
driver.Driver.Picture = *req.DriverRequest.Driver.Picture
}
if req.DriverRequest.Driver.Gender != nil {
driver.Driver.Gender = *req.DriverRequest.Driver.Gender
}
if req.DriverRequest.Driver.VerifiedIdentity != nil {
driver.Driver.VerifiedIdentity = *req.DriverRequest.Driver.VerifiedIdentity
}
if req.DriverRequest.Car != nil {
driver.Car = internal.Car{
Model: *req.DriverRequest.Car.Model,
Brand: *req.DriverRequest.Car.Brand,
}
}
if req.DriverRequest.Preferences != nil {
driver.Preferences = internal.Preferences{
Smoking: *req.DriverRequest.Preferences.Smoking,
Animals: *req.DriverRequest.Preferences.Animals,
Music: *req.DriverRequest.Preferences.Music,
Is_talker: *req.DriverRequest.Preferences.IsTalker,
Luggage_size: *req.DriverRequest.Preferences.LuggageSize,
}
}
for _, v := range req.DriverAvailabilities {
driver.RegularAvailabilities = append(driver.RegularAvailabilities, internal.RegularAvailabilities{
DayOfWeek: v.DayOfWeek.String(),
StartTime: v.StartTime,
EndTime: v.EndTime,
})
}
err = s.Handler.SetDriverAvailabilities(context.Background(), driver)
if err != nil {
return &proto.DriverAvailabilitiesResponse{
Success: false,
}, err
}
return &proto.DriverAvailabilitiesResponse{
Success: true,
}, nil
}
func (s *SolidarityServiceServerImpl) SetDriverPunctualAvailabilities(ctx context.Context, req *proto.DriverPunctualAvailabilities) (resp *proto.DriverAvailabilitiesResponse, err error) {
if req.DriverRequest.Driver.Id == "" || req.DriverRequest.Driver.Alias == "" || req.DriverAvailabilities == nil || req.DriverRequest.DriverAddress == nil || req.DriverRequest.DriverRadius == 0 {
return &proto.DriverAvailabilitiesResponse{
Success: false,
}, errors.New("missing required fields")
}
driver := internal.Driver{
Driver_departure_address: &geojson.Feature{
Type: "Feature",
Geometry: orb.Geometry(orb.Point{req.DriverRequest.DriverAddress.Lat, req.DriverRequest.DriverAddress.Long}),
Properties: geojson.Properties{
"name": req.DriverRequest.DriverAddress.Address,
},
},
Radius: req.DriverRequest.DriverRadius,
Driver: internal.User{
ID: req.DriverRequest.Driver.Id,
Alias: req.DriverRequest.Driver.Alias,
},
AvailabilitiesType: internal.Punctual,
}
if req.DriverRequest.Driver.FirstName != nil {
driver.Driver.FirstName = *req.DriverRequest.Driver.FirstName
}
if req.DriverRequest.Driver.LastName != nil {
driver.Driver.LastName = *req.DriverRequest.Driver.LastName
}
if req.DriverRequest.Driver.Grade != nil {
driver.Driver.Grade = *req.DriverRequest.Driver.Grade
}
if req.DriverRequest.Driver.Picture != nil {
driver.Driver.Picture = *req.DriverRequest.Driver.Picture
}
if req.DriverRequest.Driver.Gender != nil {
driver.Driver.Gender = *req.DriverRequest.Driver.Gender
}
if req.DriverRequest.Driver.VerifiedIdentity != nil {
driver.Driver.VerifiedIdentity = *req.DriverRequest.Driver.VerifiedIdentity
}
if req.DriverRequest.Car != nil {
driver.Car = internal.Car{
Model: *req.DriverRequest.Car.Model,
Brand: *req.DriverRequest.Car.Brand,
}
}
if req.DriverRequest.Preferences != nil {
driver.Preferences = internal.Preferences{
Smoking: *req.DriverRequest.Preferences.Smoking,
Animals: *req.DriverRequest.Preferences.Animals,
Music: *req.DriverRequest.Preferences.Music,
Is_talker: *req.DriverRequest.Preferences.IsTalker,
Luggage_size: *req.DriverRequest.Preferences.LuggageSize,
}
}
for _, v := range req.DriverAvailabilities {
driver.PunctualAvailabilities = append(driver.PunctualAvailabilities, internal.PunctualAvailabilities{
Date: v.Date.Seconds,
StartTime: v.StartTime,
EndTime: v.EndTime,
})
}
err = s.Handler.SetDriverAvailabilities(context.Background(), driver)
if err != nil {
return &proto.DriverAvailabilitiesResponse{
Success: false,
}, err
}
return &proto.DriverAvailabilitiesResponse{
Success: true,
}, nil
}
func (s *SolidarityServiceServerImpl) CreateBooking(ctx context.Context, req *proto.CreateBookingRequest) (resp *proto.CreateBookingResponse, err error) {
if req.Booking.DriverId == "" || req.Booking.PassengerId == "" || req.Booking.Id == "" || req.Booking.Status.String() == "" {
return nil, errors.New("missing required fields")
}
bookingRequest := internal.BookingRequest{
ID: req.Booking.Id,
Passenger_id: req.Booking.PassengerId,
Driver_id: req.Booking.DriverId,
Status: internal.BookingStatus(req.Booking.Status),
}
passenger, driver, err := s.Handler.CreateBooking(context.Background(), bookingRequest)
if err != nil {
return nil, err
}
duration, err := s.Handler.CalculateDurationBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
if err != nil {
duration = 0
}
distance := s.Handler.CalculateDistanceBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
priceType := proto.PriceType_FREE
resp.Booking = &proto.Booking{
Id: bookingRequest.ID,
Driver: &proto.User{
Id: driver.Driver.ID,
Alias: driver.Driver.Alias,
FirstName: &driver.Driver.FirstName,
LastName: &driver.Driver.LastName,
Grade: &driver.Driver.Grade,
Picture: &driver.Driver.Picture,
Gender: &driver.Driver.Gender,
VerifiedIdentity: &driver.Driver.VerifiedIdentity,
},
Passenger: &proto.User{
Id: passenger.Passenger.ID,
Alias: passenger.Passenger.Alias,
FirstName: &passenger.Passenger.FirstName,
LastName: &passenger.Passenger.LastName,
Grade: &passenger.Passenger.Grade,
Picture: &passenger.Passenger.Picture,
Gender: &passenger.Passenger.Gender,
VerifiedIdentity: &passenger.Passenger.VerifiedIdentity,
},
PassengerPickupDate: &timestamp.Timestamp{
Seconds: passenger.Passenger_pickup_date,
},
PassengerDepartureRoute: &proto.Feature{
Lat: passenger.Passenger_departure_address.Point().Lat(),
Long: passenger.Passenger_departure_address.Point().Lon(),
Address: passenger.Passenger_departure_address.Properties.MustString("name"),
},
PassengerDestinationRoute: &proto.Feature{
Lat: passenger.Passenger_destination_address.Point().Lat(),
Long: passenger.Passenger_destination_address.Point().Lon(),
Address: passenger.Passenger_destination_address.Properties.MustString("name"),
},
Status: ConvertInternalToProtoBookingStatus(bookingRequest.Status),
Duration: &duration,
Distance: &distance,
Price: &proto.Price{
Type: &priceType,
},
Car: &proto.Car{
Model: &driver.Car.Model,
Brand: &driver.Car.Brand,
},
}
return resp, nil
}
func (s *SolidarityServiceServerImpl) UpdateBooking(ctx context.Context, req *proto.UpdateBookingRequest) (resp *proto.UpdateBookingResponse, err error) {
if req.BookingId == "" || req.Status.String() == "" {
return &proto.UpdateBookingResponse{
Success: false,
}, errors.New("missing required fields")
}
bookingStatus := internal.BookingStatus(req.Status.String())
err = s.Handler.UpdateBooking(context.Background(), req.BookingId, bookingStatus)
if err != nil {
return &proto.UpdateBookingResponse{
Success: false,
}, err
}
return &proto.UpdateBookingResponse{
Success: true,
}, nil
}
func (s *SolidarityServiceServerImpl) GetBooking(ctx context.Context, req *proto.GetBookingRequest) (resp *proto.GetBookingResponse, err error) {
if req.BookingId == "" {
return nil, errors.New("empty booking ID")
}
booking, passenger, driver, err := s.Handler.GetBooking(context.Background(), req.BookingId)
if err != nil {
return nil, err
}
duration, err := s.Handler.CalculateDurationBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
if err != nil {
duration = 0
}
distance := s.Handler.CalculateDistanceBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
priceType := proto.PriceType_FREE
resp.Booking = &proto.Booking{
Id: booking.ID,
Driver: &proto.User{
Id: driver.Driver.ID,
Alias: driver.Driver.Alias,
FirstName: &driver.Driver.FirstName,
LastName: &driver.Driver.LastName,
Grade: &driver.Driver.Grade,
Picture: &driver.Driver.Picture,
Gender: &driver.Driver.Gender,
VerifiedIdentity: &driver.Driver.VerifiedIdentity,
},
Passenger: &proto.User{
Id: passenger.Passenger.ID,
Alias: passenger.Passenger.Alias,
FirstName: &passenger.Passenger.FirstName,
LastName: &passenger.Passenger.LastName,
Grade: &passenger.Passenger.Grade,
Picture: &passenger.Passenger.Picture,
Gender: &passenger.Passenger.Gender,
VerifiedIdentity: &passenger.Passenger.VerifiedIdentity,
},
PassengerPickupDate: &timestamp.Timestamp{
Seconds: passenger.Passenger_pickup_date,
},
PassengerDepartureRoute: &proto.Feature{
Lat: passenger.Passenger_departure_address.Point().Lat(),
Long: passenger.Passenger_departure_address.Point().Lon(),
Address: passenger.Passenger_departure_address.Properties.MustString("name"),
},
PassengerDestinationRoute: &proto.Feature{
Lat: passenger.Passenger_destination_address.Point().Lat(),
Long: passenger.Passenger_destination_address.Point().Lon(),
Address: passenger.Passenger_destination_address.Properties.MustString("name"),
},
Status: ConvertInternalToProtoBookingStatus(booking.Status),
Duration: &duration,
Distance: &distance,
Price: &proto.Price{
Type: &priceType,
},
Car: &proto.Car{
Model: &driver.Car.Model,
Brand: &driver.Car.Brand,
},
}
return resp, nil
}
func (s *SolidarityServiceServerImpl) GetBookingsByStatus(ctx context.Context, req *proto.GetBookingsByStatusRequest) (resp *proto.GetBookingsByStatusResponse, err error) {
if req.Type.String() == "" || req.Status.String() == "" || req.UserId == "" {
return nil, errors.New("missing required fields")
}
bookings, err := s.Handler.GetBookingsByStatus(context.Background(), req.Status.String(), req.Type.String(), req.UserId)
if err != nil {
return nil, err
}
responses := []*proto.Booking{}
for _, v := range bookings {
passenger, err := s.Handler.GetPassenger(context.Background(), v.Passenger.ID)
if err != nil {
return nil, err
}
driver, err := s.Handler.GetDriver(context.Background(), v.Driver.ID)
if err != nil {
return nil, err
}
duration, err := s.Handler.CalculateDurationBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
if err != nil {
duration = 0
}
priceType := proto.PriceType_FREE
distance := s.Handler.CalculateDistanceBetweenFeatures(passenger.Passenger_departure_address, passenger.Passenger_destination_address)
responses = append(responses, &proto.Booking{
Id: v.ID,
Status: ConvertInternalToProtoBookingStatus(v.Status),
Driver: &proto.User{
Id: v.Driver.ID,
Alias: driver.Driver.Alias,
FirstName: &driver.Driver.FirstName,
LastName: &driver.Driver.LastName,
Grade: &driver.Driver.Grade,
Picture: &driver.Driver.Picture,
Gender: &driver.Driver.Gender,
VerifiedIdentity: &driver.Driver.VerifiedIdentity,
},
Passenger: &proto.User{
Id: v.Passenger.ID,
Alias: passenger.Passenger.Alias,
FirstName: &passenger.Passenger.FirstName,
LastName: &passenger.Passenger.LastName,
Grade: &passenger.Passenger.Grade,
Picture: &passenger.Passenger.Picture,
Gender: &passenger.Passenger.Gender,
VerifiedIdentity: &passenger.Passenger.VerifiedIdentity,
},
PassengerPickupDate: &timestamp.Timestamp{
Seconds: passenger.Passenger_pickup_date,
},
PassengerDepartureRoute: &proto.Feature{
Lat: passenger.Passenger_departure_address.Point().Lat(),
Long: passenger.Passenger_departure_address.Point().Lon(),
Address: passenger.Passenger_departure_address.Properties.MustString("name"),
},
PassengerDestinationRoute: &proto.Feature{
Lat: passenger.Passenger_destination_address.Point().Lat(),
Long: passenger.Passenger_destination_address.Point().Lon(),
Address: passenger.Passenger_destination_address.Properties.MustString("name"),
},
Duration: &duration,
Distance: &distance,
Car: &proto.Car{
Model: &driver.Car.Model,
Brand: &driver.Car.Brand,
},
Price: &proto.Price{
Type: &priceType,
},
})
}
resp.Booking = responses
return resp, nil
}
func (s *SolidarityServiceServerImpl) DriverJourneys(ctx context.Context, req *proto.DriverJourneysRequest) (resp *proto.DriverJourneysResponse, err error) {
if req.DepartureDate.Seconds == 0 || req.Departure == nil {
return nil, errors.New("missing required fields")
}
drivers, err := s.Handler.GetDriverJourneys(context.Background(), &geojson.Feature{
Type: "Feature",
Geometry: orb.Geometry(orb.Point{req.Departure.Lat, req.Departure.Long}),
Properties: geojson.Properties{
"name": req.Departure.Address,
}},
req.DepartureDate.Seconds)
if err != nil {
return nil, err
}
response := []*proto.DriverJourney{}
for _, v := range drivers {
temp := &proto.DriverJourney{}
if v.AvailabilitiesType == internal.Regular && v.RegularAvailabilities != nil {
regularAvailabilities := make([]*proto.RegularAvailabilitySlot, 0) // Initialize an empty slice
for _, v := range v.RegularAvailabilities {
day := ConvertToProtoDayOfTheWeek(v.DayOfWeek)
regularAvailabilities = append(regularAvailabilities, &proto.RegularAvailabilitySlot{
DayOfWeek: day,
StartTime: v.StartTime,
EndTime: v.EndTime,
})
}
convertedAvailability := &proto.RepeatedRegularAvailabilitySlot{
RegularAvailabilities: regularAvailabilities,
}
temp.Availabilities = &proto.DriverJourney_RepeatedRegularAvailabilities{
RepeatedRegularAvailabilities: convertedAvailability,
}
} else if v.AvailabilitiesType == internal.Punctual && v.PunctualAvailabilities != nil {
punctualAvailabilities := make([]*proto.PunctualAvailabilitySlot, 0) // Initialize an empty slice
for _, v := range v.PunctualAvailabilities {
punctualAvailabilities = append(punctualAvailabilities, &proto.PunctualAvailabilitySlot{
Date: &timestamp.Timestamp{
Seconds: v.Date,
},
StartTime: v.StartTime,
EndTime: v.EndTime,
})
}
convertedAvailability := &proto.RepeatedPunctualAvailabilitySlot{
PunctualAvailabilities: punctualAvailabilities,
}
temp.Availabilities = &proto.DriverJourney_RepeatedPunctualAvailabilities{
RepeatedPunctualAvailabilities: convertedAvailability,
}
}
priceType := proto.PriceType_FREE
tamp := &proto.DriverJourney{
User: &proto.User{
Id: v.Driver.ID,
Alias: v.Driver.Alias,
FirstName: &v.Driver.FirstName,
LastName: &v.Driver.LastName,
Grade: &v.Driver.Grade,
Picture: &v.Driver.Picture,
Gender: &v.Driver.Gender,
VerifiedIdentity: &v.Driver.VerifiedIdentity,
},
Car: &proto.Car{
Model: &v.Car.Model,
Brand: &v.Car.Brand,
},
DriverDeparture_Date: &timestamp.Timestamp{
Seconds: req.DepartureDate.Seconds,
},
Price: &proto.Price{
Type: &priceType,
},
DriverDeparture_Address: v.Driver_departure_address.Properties.MustString("name"),
}
temp.DriverDeparture_Address = tamp.DriverDeparture_Address
temp.Car = tamp.Car
temp.User = tamp.User
temp.DriverDeparture_Date = tamp.DriverDeparture_Date
temp.Price = tamp.Price
response = append(response, temp)
}
resp.DriverJourneys = response
return resp, nil
}
func (s *SolidarityServiceServerImpl) SetPassengerTrip(ctx context.Context, req *proto.PassengerTripRequest) (resp *proto.PassengerTripResponse, err error) {
if req.Passenger.Id == "" || req.Passenger.Alias == "" || req.PassengerPickupDate.Seconds == 0 || req.PassengerDestinationAddress == nil || req.PassengerDestinationAddress == nil {
return &proto.PassengerTripResponse{
Success: false,
}, errors.New("missing required fields")
}
passenger := internal.Passenger{
Passenger_departure_address: &geojson.Feature{
Type: "Feature",
Geometry: orb.Geometry(orb.Point{req.PassengerDepartureAddress.Lat, req.PassengerDepartureAddress.Long}),
Properties: geojson.Properties{
"name": req.PassengerDepartureAddress.Address,
},
},
Passenger_destination_address: &geojson.Feature{
Type: "Feature",
Geometry: orb.Geometry(orb.Point{req.PassengerDestinationAddress.Lat, req.PassengerDestinationAddress.Long}),
Properties: geojson.Properties{
"name": req.PassengerDestinationAddress.Address,
},
},
Passenger_pickup_date: req.PassengerPickupDate.Seconds,
Passenger: internal.User{
ID: req.Passenger.Id,
Alias: req.Passenger.Alias,
},
}
if req.Passenger.FirstName != nil {
passenger.Passenger.FirstName = *req.Passenger.FirstName
}
if req.Passenger.LastName != nil {
passenger.Passenger.LastName = *req.Passenger.LastName
}
if req.Passenger.Grade != nil {
passenger.Passenger.Grade = *req.Passenger.Grade
}
if req.Passenger.Picture != nil {
passenger.Passenger.Picture = *req.Passenger.Picture
}
if req.Passenger.Gender != nil {
passenger.Passenger.Gender = *req.Passenger.Gender
}
if req.Passenger.VerifiedIdentity != nil {
passenger.Passenger.VerifiedIdentity = *req.Passenger.VerifiedIdentity
}
if req.Preferences != nil {
passenger.Preferences = internal.Preferences{
Smoking: *req.Preferences.Smoking,
Animals: *req.Preferences.Animals,
Music: *req.Preferences.Music,
Is_talker: *req.Preferences.IsTalker,
Luggage_size: *req.Preferences.LuggageSize,
}
}
err = s.Handler.SetPassengerTrip(context.Background(), passenger)
if err != nil {
return &proto.PassengerTripResponse{
Success: false,
}, nil
}
return &proto.PassengerTripResponse{
Success: true,
}, nil
}

22
servers/utils/utils.go Normal file
View File

@ -0,0 +1,22 @@
package utils
import "math"
func Haversine(lat1, lon1, lat2, lon2 float64) float64 {
// Radius of the Earth in kilometers
R := 6371.0
lat1 = lat1 * math.Pi / 180
lon1 = lon1 * math.Pi / 180
lat2 = lat2 * math.Pi / 180
lon2 = lon2 * math.Pi / 180
dlat := lat2 - lat1
dlon := lon2 - lon1
a := math.Sin(dlat/2)*math.Sin(dlat/2) + math.Cos(lat1)*math.Cos(lat2)*math.Sin(dlon/2)*math.Sin(dlon/2)
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
distance := R * c
return distance
}

558
storage/postgresql.go Normal file
View File

@ -0,0 +1,558 @@
package storage
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"github.com/google/uuid"
_ "github.com/lib/pq"
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
"solidarity-service/internal"
"solidarity-service/servers/utils"
"strconv"
"strings"
"time"
)
type PostgresqlStorage struct {
DbConnection *sql.DB
Schema string
Tables map[string]string
}
func NewPostgresqlStorage(cfg *viper.Viper) (PostgresqlStorage, error) {
var (
host = cfg.GetString("storage.db.psql.host")
port = cfg.GetString("storage.db.psql.port")
user = cfg.GetString("storage.db.psql.user")
password = cfg.GetString("storage.db.psql.password")
dbname = cfg.GetString("storage.db.psql.dbname")
sslmode = cfg.GetString("storage.db.psql.sslmode")
pg_schema = cfg.GetString("storage.db.psql.schema")
pgtables_drivers = cfg.GetString("storage.db.psql.tables.drivers")
pgtables_passengers = cfg.GetString("storage.db.psql.tables.passengers")
pgtables_bookings = cfg.GetString("storage.db.psql.tables.bookings")
)
portInt, _ := strconv.Atoi(port)
psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s", host, portInt, user, password, dbname, sslmode)
db, err := sql.Open("postgres", psqlconn)
if err != nil {
log.Error().Err(err).Msg("opening connection to postgresql failed")
return PostgresqlStorage{}, fmt.Errorf("connection to postgresql failed")
}
err = db.Ping()
if err != nil {
log.Error().Err(err).Msg("ping to postgresql failed")
return PostgresqlStorage{}, fmt.Errorf("connection to postgresql database failed")
}
return PostgresqlStorage{
DbConnection: db,
Schema: pg_schema,
Tables: map[string]string{
"drivers": fmt.Sprintf("%s.%s", pg_schema, pgtables_drivers),
"bookings": fmt.Sprintf("%s.%s", pg_schema, pgtables_bookings),
"passengers": fmt.Sprintf("%s.%s", pg_schema, pgtables_passengers),
},
}, nil
}
func (s PostgresqlStorage) CreatePassenger(passenger internal.Passenger) (err error) {
_, err = uuid.Parse(passenger.Passenger.ID)
if err != nil {
log.Error().Err(err).Msg("Postgresql Storage CreatePassenger invalid ID")
return err
}
if passenger.Passenger_pickup_date == 0 {
errMsg := "Postgresql Storage CreatePassenger empty UNIX pickup Date timestamp"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
if passenger.Passenger.Alias == "" || passenger.Passenger.Operator == "" {
errMsg := "Postgresql Storage CreatePassenger empty alias or operator FQDN."
log.Error().Msg(errMsg)
return errors.New(errMsg)
}
preferencesJSON, err := json.Marshal(passenger.Preferences)
if err != nil {
errMsg := "Postgresql Storage CreatePassenger Error encoding Preferences to JSON"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
departureJSON, err := json.Marshal(passenger.Passenger_departure_address)
if err != nil {
errMsg := "Postgresql Storage CreatePassenger Error encoding departure Feature to JSON"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
destinationJSON, err := json.Marshal(passenger.Passenger_destination_address)
if err != nil {
errMsg := "Postgresql Storage CreatePassenger Error converting destination Feature to JSON"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
_, err = s.DbConnection.Exec(fmt.Sprintf("INSERT INTO %s (passenger_id, passenger_departure_route, passenger_destination_route, alias, last_name, first_name, grade, picture, verified_identity, operator, preferences, passenger_pickup_date) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)", s.Tables["passengers"]),
passenger.Passenger.ID,
departureJSON,
destinationJSON,
passenger.Passenger.Alias,
passenger.Passenger.LastName,
passenger.Passenger.FirstName,
passenger.Passenger.Grade,
passenger.Passenger.Picture,
passenger.Passenger.VerifiedIdentity,
passenger.Passenger.Operator,
preferencesJSON,
passenger.Passenger_pickup_date)
if err != nil {
errMsg := "Postgresql Storage CreatePassenger Error inserting data into the database"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
return nil
}
func (s PostgresqlStorage) GetPassenger(passengerID string) (passenger internal.Passenger, err error) {
var preferencesJSON []byte
var departure_address []byte
var destination_address []byte
err = s.DbConnection.QueryRow(fmt.Sprintf("SELECT passenger_departure_route, passenger_destination_route, alias, last_name, first_name, grade, picture, verified_identity, operator, preferences, passenger_pickup_date , passenger_id FROM %s WHERE passenger_id = $1", s.Tables["passengers"]), passengerID).
Scan(
&departure_address,
&destination_address,
&passenger.Passenger.Alias,
&passenger.Passenger.LastName,
&passenger.Passenger.FirstName,
&passenger.Passenger.Grade,
&passenger.Passenger.Picture,
&passenger.Passenger.VerifiedIdentity,
&passenger.Passenger.Operator,
&preferencesJSON,
&passenger.Passenger_pickup_date,
&passenger.Passenger.ID,
)
if err != nil {
fmt.Println(err)
errMsg := "Postgresql Storage GetPassenger Error querying data from the database"
log.Error().Err(err).Msg(errMsg)
return passenger, errors.New(errMsg)
}
err = json.Unmarshal(preferencesJSON, &passenger.Preferences)
if err != nil {
errMsg := "Postgresql Storage GetPassenger Error decoding Preferences from JSON"
log.Error().Err(err).Msg(errMsg)
return passenger, errors.New(errMsg)
}
passenger.Passenger_destination_address, err = geojson.UnmarshalFeature(destination_address)
if err != nil {
errMsg := "Postgresql Storage GetPassenger Error decoding Passenger destination route into GeoJSON"
log.Error().Err(err).Msg(errMsg)
return passenger, errors.New(errMsg)
}
passenger.Passenger_departure_address, err = geojson.UnmarshalFeature(departure_address)
if err != nil {
errMsg := "Postgresql Storage GetPassenger Error decoding Passenger departure route into GeoJSON"
log.Error().Err(err).Msg(errMsg)
return passenger, errors.New(errMsg)
}
return passenger, nil
}
func (s PostgresqlStorage) CreateDriver(driver internal.Driver) (err error) {
var availabilities []byte
_, err = uuid.Parse(driver.Driver.ID)
if err != nil {
log.Error().Err(err).Msg("Postgresql Storage CreateDriver invalid ID")
return err
}
departureJSON, err := json.Marshal(driver.Driver_departure_address)
if err != nil {
errMsg := "Postgresql Storage CreateDriver Error encoding departure Feature to JSON"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
preferencesJSON, err := json.Marshal(driver.Preferences)
if err != nil {
errMsg := "Postgresql Storage CreateDriver Error encoding Preferences to JSON"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
carJSON, err := json.Marshal(driver.Car)
if err != nil {
errMsg := "Postgresql Storage CreateDriver Error encoding Car to JSON"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
if driver.Driver.Alias == "" || driver.Driver.Operator == "" {
errMsg := "Postgresql Storage CreateDriver empty alias or operator FQDN."
log.Error().Msg(errMsg)
return errors.New(errMsg)
}
if driver.AvailabilitiesType != internal.Punctual && driver.AvailabilitiesType != internal.Regular {
errMsg := "Postgresql Storage CreateDriver invalid Availabilities Type"
log.Error().Msg(errMsg)
return errors.New(errMsg)
}
if driver.Radius == 0 {
errMsg := "Postgresql Storage CreateDriver Radius has to be defined"
log.Error().Msg(errMsg)
return errors.New(errMsg)
}
switch driver.AvailabilitiesType {
case internal.Punctual:
availabilities, err = json.Marshal(driver.PunctualAvailabilities)
if err != nil {
errMsg := "Postgresql Storage CreateDriver error converting Punctual availabilities"
log.Error().Msg(errMsg)
return errors.New(errMsg)
}
case internal.Regular:
availabilities, err = json.Marshal(driver.RegularAvailabilities)
if err != nil {
errMsg := "Postgresql Storage CreateDriver error converting Regular availabilities"
log.Error().Msg(errMsg)
return errors.New(errMsg)
}
}
_, err = s.DbConnection.Exec(fmt.Sprintf("INSERT INTO %s (driver_id,driver_departure_route,driver_radius,last_name,first_name,grade,alias,picture,verified_identity,preferences,availabilities_type,availabilities,operator , car) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14)", s.Tables["drivers"]),
driver.Driver.ID,
departureJSON,
driver.Radius,
driver.Driver.LastName,
driver.Driver.FirstName,
driver.Driver.Grade,
driver.Driver.Alias,
driver.Driver.Picture,
driver.Driver.VerifiedIdentity,
preferencesJSON,
driver.AvailabilitiesType,
string(availabilities),
driver.Driver.Operator,
carJSON,
)
if err != nil {
fmt.Println(err)
errMsg := "Postgresql Storage CreateDriver Error inserting data into the database"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
return nil
}
func (s PostgresqlStorage) GetDriver(driverID string) (driver internal.Driver, err error) {
var preferencesJSON []byte
var departureAddress []byte
var availabilitiesJSON []byte
var carJSON []byte
err = s.DbConnection.QueryRow(fmt.Sprintf("SELECT driver_departure_route, driver_radius, last_name, first_name, grade, alias, picture, verified_identity, preferences, availabilities_type, availabilities, operator , driver_id , car FROM %s WHERE driver_id = $1", s.Tables["drivers"]), driverID).
Scan(
&departureAddress,
&driver.Radius,
&driver.Driver.LastName,
&driver.Driver.FirstName,
&driver.Driver.Grade,
&driver.Driver.Alias,
&driver.Driver.Picture,
&driver.Driver.VerifiedIdentity,
&preferencesJSON,
&driver.AvailabilitiesType,
&availabilitiesJSON,
&driver.Driver.Operator,
&driver.Driver.ID,
&carJSON,
)
if err != nil {
errMsg := "Postgresql Storage GetDriver Error querying data from the database"
log.Error().Err(err).Msg(errMsg)
return driver, errors.New(errMsg)
}
err = json.Unmarshal(preferencesJSON, &driver.Preferences)
if err != nil {
errMsg := "Postgresql Storage GetDriver Error decoding Preferences from JSON"
log.Error().Err(err).Msg(errMsg)
return driver, errors.New(errMsg)
}
err = json.Unmarshal(carJSON, &driver.Car)
if err != nil {
errMsg := "Postgresql Storage GetDriver Error decoding Car from JSON"
log.Error().Err(err).Msg(errMsg)
return driver, errors.New(errMsg)
}
driver.Driver_departure_address, err = geojson.UnmarshalFeature(departureAddress)
if err != nil {
errMsg := "Postgresql Storage GetDriver Error decoding Driver departure route into GeoJSON"
log.Error().Err(err).Msg(errMsg)
return driver, errors.New(errMsg)
}
switch driver.AvailabilitiesType {
case internal.Regular:
err = json.Unmarshal(availabilitiesJSON, &driver.RegularAvailabilities)
if err != nil {
errMsg := "Postgresql Storage GetDriver Error decoding Regular Availabilities from JSON"
log.Error().Err(err).Msg(errMsg)
return driver, errors.New(errMsg)
}
case internal.Punctual:
err = json.Unmarshal(availabilitiesJSON, &driver.PunctualAvailabilities)
if err != nil {
errMsg := "Postgresql Storage GetDriver Error decoding Punctual Availabilities from JSON"
log.Error().Err(err).Msg(errMsg)
return driver, errors.New(errMsg)
}
default:
errMsg := "Postgresql Storage GetDriver Invalid Availabilities Type"
log.Error().Msg(errMsg)
return driver, errors.New(errMsg)
}
return driver, nil
}
func (s PostgresqlStorage) CreateBooking(booking internal.BookingRequest) (err error) {
_, err = uuid.Parse(booking.Driver_id)
if err != nil {
log.Error().Err(err).Msg("Postgresql Storage CreateBooking invalid Driver ID")
return err
}
_, err = uuid.Parse(booking.Passenger_id)
if err != nil {
log.Error().Err(err).Msg("Postgresql Storage CreateBooking invalid Passenger ID")
return err
}
_, err = uuid.Parse(booking.ID)
if err != nil {
log.Error().Err(err).Msg("Postgresql Storage CreateBooking invalid Booking ID")
return err
}
if booking.Operator == "" {
log.Error().Err(err).Msg("Postgresql Storage CreateBooking empty operator")
return err
}
_, err = s.DbConnection.Exec(fmt.Sprintf("INSERT INTO %s (booking_id , passenger_id , driver_id , operator, booking_status) VALUES ($1,$2,$3,$4,$5)", s.Tables["bookings"]),
booking.ID,
booking.Passenger_id,
booking.Driver_id,
booking.Operator,
booking.Status,
)
if err != nil {
errMsg := "Postgresql Storage CreateBooking Error inserting data into the database"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
return nil
}
func (s PostgresqlStorage) GetBooking(id string) (booking internal.Booking, err error) {
err = s.DbConnection.QueryRow(fmt.Sprintf("SELECT booking_id , passenger_id , driver_id , booking_status FROM %s WHERE booking_id = $1", s.Tables["bookings"]), id).
Scan(
&booking.ID,
&booking.Passenger.ID,
&booking.Driver.ID,
&booking.Status,
)
fmt.Println(err)
if err != nil {
errMsg := "Postgresql Storage GetBooking Error getting booking"
log.Error().Err(err).Msg(errMsg)
return booking, errors.New(errMsg + err.Error())
}
passenger, err := s.GetPassenger(booking.Passenger.ID)
if err != nil {
errMsg := "Postgresql Storage GetBooking Error getting passenger"
log.Error().Err(err).Msg(errMsg)
return booking, errors.New(errMsg + err.Error())
}
booking.Passenger = passenger.Passenger
booking.PassengerPickupAddress = passenger.Passenger_departure_address
booking.PassengerDropAddress = passenger.Passenger_destination_address
driver, err := s.GetDriver(booking.Driver.ID)
if err != nil {
errMsg := "Postgresql Storage GetBooking Error getting driver"
log.Error().Err(err).Msg(errMsg)
return booking, errors.New(errMsg + err.Error())
}
booking.Driver = driver.Driver
return booking, nil
}
func (s PostgresqlStorage) UpdateBookingStatus(id string, status internal.BookingStatus) (err error) {
_, err = uuid.Parse(id)
if err != nil {
log.Error().Err(err).Msg("Postgresql Storage UpdateBookingStatus invalid Booking ID")
return err
}
_, err = s.GetBooking(id)
if err != nil {
return errors.New(err.Error())
}
query := fmt.Sprintf("UPDATE %s SET booking_status = $1 WHERE booking_id = $2", s.Tables["bookings"])
_, err = s.DbConnection.Exec(query, status, id)
if err != nil {
errMsg := "Postgresql Storage UpdateBookingStatus Error updating booking status"
log.Error().Err(err).Msg(errMsg)
return errors.New(errMsg)
}
return nil
}
func (s PostgresqlStorage) FilterUserBookingsByStatus(user_type string, status internal.BookingStatus, user_id string) (bookings []internal.Booking, err error) {
_, err = uuid.Parse(user_id)
if err != nil {
return nil, errors.New("invalid uuid")
}
if user_type != "driver" && user_type != "passenger" {
return nil, errors.New("invalid user type")
}
switch user_type {
case "driver":
rows, err := s.DbConnection.Query(fmt.Sprintf("SELECT booking_id, passenger_id, driver_id, booking_status FROM %s WHERE driver_id = $1 AND booking_status = $2", s.Tables["bookings"]),
user_id, status)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var booking internal.Booking
if err := rows.Scan(&booking.ID, &booking.Passenger.ID, &booking.Driver.ID, &booking.Status); err != nil {
return nil, err
}
bookings = append(bookings, booking)
}
if err := rows.Err(); err != nil {
return nil, err
}
case "passenger":
rows, err := s.DbConnection.Query(fmt.Sprintf("SELECT booking_id, passenger_id, driver_id, booking_status FROM %s WHERE passenger_id = $1 AND booking_status = $2", s.Tables["bookings"]),
user_id, status)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var booking internal.Booking
if err := rows.Scan(&booking.ID, &booking.Passenger.ID, &booking.Driver.ID, &booking.Status); err != nil {
return nil, err
}
bookings = append(bookings, booking)
}
if err := rows.Err(); err != nil {
return nil, err
}
}
return bookings, nil
}
func (s PostgresqlStorage) GetAllDrivers(date int64) (drivers []internal.Driver, err error) {
rows, err := s.DbConnection.Query(fmt.Sprintf("SELECT driver_id, driver_departure_route, driver_radius, last_name, first_name, grade, alias, picture, verified_identity, preferences, availabilities_type, availabilities, operator, car FROM %s", s.Tables["drivers"]))
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var driver internal.Driver
var departureRoute []byte
var preferencesJSON []byte
var availabilitiesJSON []byte
var carJSON []byte
if err := rows.Scan(
&driver.Driver.ID,
&departureRoute,
&driver.Radius,
&driver.Driver.LastName,
&driver.Driver.FirstName,
&driver.Driver.Grade,
&driver.Driver.Alias,
&driver.Driver.Picture,
&driver.Driver.VerifiedIdentity,
&preferencesJSON,
&driver.AvailabilitiesType,
&availabilitiesJSON,
&driver.Driver.Operator,
&carJSON,
); err != nil {
return nil, err
}
if err := json.Unmarshal(departureRoute, &driver.Driver_departure_address); err != nil {
return nil, err
}
if err := json.Unmarshal(preferencesJSON, &driver.Preferences); err != nil {
return nil, err
}
if err := json.Unmarshal(carJSON, &driver.Car); err != nil {
return nil, err
}
// Filter drivers based on date matching punctual or regular availabilities.
if driver.AvailabilitiesType == internal.Punctual {
if err := json.Unmarshal(availabilitiesJSON, &driver.PunctualAvailabilities); err != nil {
return nil, err
}
// Convert the date to the day of the week and make it lowercase.
dayOfWeek := strings.ToLower(time.Unix(date, 0).UTC().Format("Mon"))
for _, avail := range driver.PunctualAvailabilities {
// Extract the day part of the punctual driver's date and compare.
availDate := time.Unix(avail.Date, 0)
if strings.ToLower(availDate.Format("Mon")) == dayOfWeek {
drivers = append(drivers, driver)
break
}
}
} else if driver.AvailabilitiesType == internal.Regular {
if err := json.Unmarshal(availabilitiesJSON, &driver.RegularAvailabilities); err != nil {
return nil, err
}
// Convert the date to the day of the week and make it lowercase.
dayOfWeek := strings.ToLower(time.Unix(date, 0).UTC().Format("Mon"))
for _, avail := range driver.RegularAvailabilities {
if strings.ToLower(avail.DayOfWeek) == dayOfWeek {
drivers = append(drivers, driver)
break
}
}
}
}
if err := rows.Err(); err != nil {
return nil, err
}
return drivers, nil
}
func (s PostgresqlStorage) DriverJourneys(departure_route *geojson.Feature, departure_date int64) (drivers []internal.Driver, err error) {
allDrivers, err := s.GetAllDrivers(departure_date)
if err != nil {
return nil, err
}
for _, driver := range allDrivers {
// Check if the departure route is the same as the driver's departure route.
if departure_route.Point().Y() == driver.Driver_departure_address.Point().Y() && departure_route.Point().X() == driver.Driver_departure_address.Point().X() {
drivers = append(drivers, driver)
} else {
// Calculate the distance between the departure point and the driver's departure route.
coords1 := departure_route.Geometry.(orb.Point)
coords2 := driver.Driver_departure_address.Geometry.(orb.Point)
distance := utils.Haversine(coords1[1], coords1[0], coords2[1], coords2[0])
if int64(distance) <= int64(driver.Radius) {
drivers = append(drivers, driver)
}
}
}
return drivers, nil
}

View File

@ -0,0 +1,168 @@
table "passengers" {
schema = schema.solidarity_service
column "passenger_id" {
null = false
type = uuid
}
column "passenger_departure_route" {
null = false
type = jsonb
}
column "passenger_destination_route" {
null = false
type = jsonb
}
column "alias" {
null = false
type = varchar(15)
}
column "last_name" {
null = true
type = text
}
column "first_name" {
null = true
type = text
}
column "grade" {
null = true
type = int
}
column "picture" {
null = true
type = varchar(200)
}
column "verified_identity"{
null = true
type = bool
}
column "operator" {
null = false
type = varchar(35)
}
column "preferences" {
null = true
type = jsonb
}
column "passenger_pickup_date" {
null = false
type = int
}
primary_key {
columns = [column.passenger_id]
}
}
table "drivers" {
schema = schema.solidarity_service
column "driver_id" {
null = false
type = uuid
}
column "driver_departure_route" {
null = false
type = jsonb
}
column "driver_radius" {
null = false
type = integer
}
column "last_name" {
null = true
type = text
}
column "first_name" {
null = true
type = text
}
column "grade" {
null = true
type = int
}
column "alias" {
null = false
type = varchar(15)
}
column "picture" {
null = true
type = text
}
column "verified_identity"{
null = true
type = bool
}
column "preferences" {
null = true
type = jsonb
}
column "availabilities_type" {
null = false
type = enum.availabilities_type
}
column "availabilities" {
null = false
type = jsonb
}
column "car" {
null = true
type = jsonb
}
column "operator" {
null = false
type = varchar(35)
}
primary_key {
columns = [column.driver_id]
}
}
table "bookings" {
schema = schema.solidarity_service
column "booking_id" {
null = false
type = uuid
}
column "driver_id" {
null = false
type = uuid
}
column "operator" {
null = false
type = varchar(35)
}
column "passenger_id" {
null = false
type = uuid
}
column "booking_status" {
null = false
type = enum.booking_status
}
primary_key {
columns = [column.booking_id]
}
foreign_key "bookings_driver_id_fkey" {
columns = [column.driver_id]
ref_columns = [table.drivers.column.driver_id]
}
foreign_key "group_members_passenger_id_fkey" {
columns = [column.passenger_id]
ref_columns = [table.passengers.column.passenger_id]
}
}
enum "booking_status" {
schema = schema.solidarity_service
values = ["INITIATED", "WAITING_PASSENGER_CONFIRMATION", "WAITING_DRIVER_CONFIRMATION", "CONFIRMED", "CANCELLED", "COMPLETED_PENDING_VALIDATION", "VALIDATED"]
}
enum "availabilities_type" {
schema = schema.solidarity_service
values = ["PUNCTUAL","REGULAR"]
}
schema "solidarity_service" {
}

34
storage/storage.go Normal file
View File

@ -0,0 +1,34 @@
package storage
import (
"fmt"
"github.com/paulmach/orb/geojson"
"github.com/spf13/viper"
"solidarity-service/internal"
)
type Storage interface {
CreatePassenger(passenger internal.Passenger) (err error)
GetPassenger(passengerID string) (passenger internal.Passenger, err error)
CreateDriver(driver internal.Driver) (err error)
GetDriver(driverID string) (driver internal.Driver, err error)
GetBooking(id string) (booking internal.Booking, err error)
CreateBooking(booking internal.BookingRequest) (err error)
UpdateBookingStatus(id string, status internal.BookingStatus) (err error)
FilterUserBookingsByStatus(user_type string, status internal.BookingStatus, user_id string) (bookings []internal.Booking, err error)
DriverJourneys(departure_route *geojson.Feature, departure_date int64) (drivers []internal.Driver, err error)
GetAllDrivers(date int64) (drivers []internal.Driver, err error)
}
func NewStorage(cfg *viper.Viper) (Storage, error) {
var (
storage_type = cfg.GetString("storage.db.type")
)
switch storage_type {
case "psql":
s, err := NewPostgresqlStorage(cfg)
return s, err
default:
return nil, fmt.Errorf("storage type %v is not supported", storage_type)
}
}