From d6956c90456197bc61452a6df8a7082679dd3b16 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Thu, 3 Aug 2023 17:27:48 +0200 Subject: [PATCH 01/35] feat(arango): add arango api to Core --- .gitignore | 6 +- ARANGO_API/database/common.go | 159 ++++++++++++ ARANGO_API/database/connection.go | 45 ++++ ARANGO_API/database/devices.go | 72 ++++++ ARANGO_API/docker-compose.yaml | 39 +++ ARANGO_API/dockerfile | 31 +++ ARANGO_API/go.mod | 51 ++++ ARANGO_API/go.sum | 255 +++++++++++++++++++ ARANGO_API/handlers/connection.go | 120 +++++++++ ARANGO_API/handlers/database.go | 95 +++++++ ARANGO_API/handlers/devices.go | 138 +++++++++++ ARANGO_API/handlers/swagger.go | 19 ++ ARANGO_API/main.go | 43 ++++ ARANGO_API/models/connections.go | 43 ++++ ARANGO_API/models/devices.go | 61 +++++ ARANGO_API/models/http.go | 54 ++++ ARANGO_API/services/router.go | 47 ++++ ARANGO_API/swagger.yaml | 396 ++++++++++++++++++++++++++++++ 18 files changed, 1673 insertions(+), 1 deletion(-) create mode 100644 ARANGO_API/database/common.go create mode 100644 ARANGO_API/database/connection.go create mode 100644 ARANGO_API/database/devices.go create mode 100644 ARANGO_API/docker-compose.yaml create mode 100644 ARANGO_API/dockerfile create mode 100644 ARANGO_API/go.mod create mode 100644 ARANGO_API/go.sum create mode 100644 ARANGO_API/handlers/connection.go create mode 100644 ARANGO_API/handlers/database.go create mode 100644 ARANGO_API/handlers/devices.go create mode 100644 ARANGO_API/handlers/swagger.go create mode 100644 ARANGO_API/main.go create mode 100644 ARANGO_API/models/connections.go create mode 100644 ARANGO_API/models/devices.go create mode 100644 ARANGO_API/models/http.go create mode 100644 ARANGO_API/services/router.go create mode 100644 ARANGO_API/swagger.yaml diff --git a/.gitignore b/.gitignore index 1ef4f328c..796caa48e 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,8 @@ unitylog.txt # APP Ignore deploy/docker/*.env -deploy/docker/app-deploy \ No newline at end of file +deploy/docker/app-deploy + +#ARANGO_API Ignore +ARANGO_API/go-api +ARANGO_API/env diff --git a/ARANGO_API/database/common.go b/ARANGO_API/database/common.go new file mode 100644 index 000000000..3e22450bc --- /dev/null +++ b/ARANGO_API/database/common.go @@ -0,0 +1,159 @@ +package database +import ( + h "net/http" + "go-api/models" + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/arangodb/go-driver/http" + driver "github.com/arangodb/go-driver" +) + + + + +func GetDBConn(c *gin.Context) (*driver.Database,*models.ErrorMessage) { + dbConn,ok:= c.Value("database").(*driver.Database) + //dbConn, ok := c.MustGet("database").(driver.Database) + if !ok { + return nil, &models.ErrorMessage{StatusCode: h.StatusInternalServerError,Message:"Failed to get database"} + } + if *dbConn == nil { + return nil, &models.ErrorMessage{StatusCode: h.StatusNotFound,Message:"Failed to get database"} + } + return dbConn, nil +} + +func ParseToString(obj interface{}) (string,*models.ErrorMessage) { + + asJson,err := json.Marshal(obj) + if err != nil{ + return "",&models.ErrorMessage{StatusCode: h.StatusInternalServerError,Message:"Failed to parse query string"} + } + return string(asJson), nil + + +} + +func ExecQuerry(db driver.Database, query string) ([]interface{}, *models.ErrorMessage) { + + var result []interface{} + cursor, err := db.Query(nil, query, nil) + + if err != nil { + return result,&models.ErrorMessage{StatusCode: h.StatusInternalServerError,Message: err.Error()} + } + + defer cursor.Close() + + for { + var doc interface{} + _ ,err = cursor.ReadDocument(nil, &doc) + if driver.IsNoMoreDocuments(err) { + break + } else if err != nil { + return result, &models.ErrorMessage{StatusCode: h.StatusInternalServerError,Message: err.Error()} + } else { + result = append(result, doc) + } + } + return result, nil + +} + +func GetAll(c *gin.Context,col string) ([]interface{},*models.ErrorMessage){ + db, err := GetDBConn(c) + if err != nil { + return nil, err + } + values := c.Request.URL.Query() + + querystring := "FOR doc IN "+col + + for key,value := range values{ + querystring += " FILTER doc."+key+" == \""+value[0]+"\" " + } + querystring += " RETURN doc" + result, err := ExecQuerry(*db, querystring); + if err != nil { + return nil, err + } + return result, nil +} + + +func Delete(c *gin.Context, key, col string) ([]interface{},*models.ErrorMessage) { + + db, err := GetDBConn(c) + if err != nil { + return nil, err + } + + querystring := "FOR doc IN "+col+" FILTER doc.`_key`== \""+key+"\" REMOVE doc IN "+col + + result, err := ExecQuerry(*db, querystring); + if err != nil { + return nil, err + } + return result,nil + +} + +func Update(c *gin.Context, doc interface{},key, col string) ([]interface{},*models.ErrorMessage) { + db, err := GetDBConn(c) + if err != nil { + return nil, err + } + + docStr, err := ParseToString(doc) + if err != nil { + return nil, err + } + querystring := "UPDATE \""+key+"\" WITH "+docStr+" IN "+col+" RETURN "+key + + result, err := ExecQuerry(*db, querystring); + if err != nil { + return nil, err + } + return result,nil +} + +func ConnectToArrengo(addr, database, user, password string) (driver.Database, *models.ErrorMessage) { + + conn, err := http.NewConnection(http.ConnectionConfig{ + Endpoints: []string{addr}, + }) + if err != nil { + return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest,Message: err.Error()} + } + + client, err := driver.NewClient(driver.ClientConfig{ + Connection: conn, + Authentication: driver.BasicAuthentication(user, password), + }) + if err != nil { + return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest,Message: err.Error()} + } + + db, err := client.Database(nil, database) + if err != nil { + return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest,Message: err.Error()} + } + return db, nil + +} + +func CreateCollection(db driver.Database, collectionName string) (driver.Collection, error) { + var col driver.Collection + coll_exists, err := db.CollectionExists(nil, collectionName) + + if !coll_exists { + col, err = db.CreateCollection(nil, collectionName, nil) + + if err != nil { + return nil, err + } + } + + return col, nil + +} \ No newline at end of file diff --git a/ARANGO_API/database/connection.go b/ARANGO_API/database/connection.go new file mode 100644 index 000000000..41457e8ae --- /dev/null +++ b/ARANGO_API/database/connection.go @@ -0,0 +1,45 @@ +package database + +import ( +// driver "github.com/arangodb/go-driver" + "github.com/gin-gonic/gin" + "go-api/models" + "net/http" + +) + +func InsertConnection(c *gin.Context, conn map[string]string) ([]interface{}, *models.ErrorMessage) { + db, err := GetDBConn(c) + if err != nil { + return nil, err + } + + // check if devices existed + existed,err := DeviceExistedById(*db, conn["_from"]) + if err != nil { + return nil, err + } + if !existed{ + return nil, &models.ErrorMessage{StatusCode: http.StatusNotFound,Message:"Device "+conn["_from"]+" not found"} + } + existed,err = DeviceExistedById(*db, conn["_to"]) + if err != nil { + return nil, err + } + if !existed{ + return nil, &models.ErrorMessage{StatusCode: http.StatusNotFound,Message:"Device "+conn["_to"]+" not found"} + } + connStr,err := ParseToString(conn) + + + if err != nil { + return nil, err + } + querystring := "INSERT "+connStr+" INTO links RETURN NEW" + + result, err := ExecQuerry(*db, querystring); + if err != nil { + return nil, err + } + return result,nil +} \ No newline at end of file diff --git a/ARANGO_API/database/devices.go b/ARANGO_API/database/devices.go new file mode 100644 index 000000000..b2bd83d56 --- /dev/null +++ b/ARANGO_API/database/devices.go @@ -0,0 +1,72 @@ +package database + +import ( + driver "github.com/arangodb/go-driver" + "github.com/gin-gonic/gin" + "go-api/models" + "net/http" + +) + + +func DeviceExistedById(db driver.Database,id string) (bool, *models.ErrorMessage) { + + querystring := "FOR devices IN devices " + querystring += "FILTER devices.`_id` == \""+id+"\" " + querystring += "RETURN devices" + + created, err := ExecQuerry(db, querystring); + if err != nil { + return false, err + } + if len(created)!=0{ + return true, nil + } + return false,nil +} +func DeviceExisted(db driver.Database,device map[string]string) (bool, *models.ErrorMessage) { + + querystring := "FOR devices IN devices " + querystring += "FILTER devices.`_name` == \""+device["_name"]+"\" " + querystring += "&& devices.`group_name` == \""+ device["group_name"]+"\" " + querystring += "&& devices.`created` == \""+ device["created"]+"\" " + querystring += "RETURN devices" + + created, err := ExecQuerry(db, querystring); + if err != nil { + return false, err + } + if len(created)!=0{ + return true, nil + } + return false,nil +} + +func InsertDevices(c *gin.Context, device map[string]string) ([]interface{}, *models.ErrorMessage) { + db, err := GetDBConn(c) + if err != nil { + return nil, err + } + + // check if devices existed + existed,err := DeviceExisted(*db, device) + if err != nil { + return nil, err + } + if existed{ + return nil,&models.ErrorMessage{StatusCode: http.StatusFound,Message:"Device already existed"} + } + deviceStr,err := ParseToString(device) + + + if err != nil { + return nil, err + } + querystring := "INSERT "+deviceStr+" INTO devices RETURN NEW" + + result, err := ExecQuerry(*db, querystring); + if err != nil { + return nil, err + } + return result,nil +} diff --git a/ARANGO_API/docker-compose.yaml b/ARANGO_API/docker-compose.yaml new file mode 100644 index 000000000..e0e8f1345 --- /dev/null +++ b/ARANGO_API/docker-compose.yaml @@ -0,0 +1,39 @@ +version: '3.9' +services: + arango_db: + image: arangodb/arangodb:3.11.2 + container_name: arango_db + environment: + - ARANGO_ROOT_PASSWORD=password + volumes: + - arangodb-persist:/var/lib/arangodb3 + ports: + - 8529:8529 + restart: on-failure:10 + + + arrango_api: + build: + dockerfile: Dockerfile + image: arango-api:latest + restart: always + container_name: arango_api + environment: + - ENV=production + - ARRANGO_URL=http://arango_db:8529 + - ARRANGO_DATABASE=_system + - ARRANGO_USER=root + - ARRANGO_PASSWORD=password + ports: + - 8080:8080 + healthcheck: + test: ["CMD", "curl","-f","http://arango_db:5829/_api/version"] + timeout: 30s + interval: 1m + retries: 3 + +volumes: + arangodb-persist: + external: true + + \ No newline at end of file diff --git a/ARANGO_API/dockerfile b/ARANGO_API/dockerfile new file mode 100644 index 000000000..b17466484 --- /dev/null +++ b/ARANGO_API/dockerfile @@ -0,0 +1,31 @@ +FROM golang:1.18.2-alpine3.16 AS build + +# Set the Current Working Directory inside the container +WORKDIR /build + +# We want to populate the module cache based on the go.{mod,sum} files. +COPY go.mod . +COPY go.sum . + +RUN go mod download + +COPY . . +RUN cp env .env + + +# Build the Go app +RUN CGO_ENABLED=0 GOOS=linux go build -a -o go-api -ldflags "-X main.version=${VERSION} -X 'main.build=$(date)'" . + +# Start fresh from a smaller image +FROM alpine:3.16 + +WORKDIR /bin + +COPY --from=build /build/go-api . +COPY --from=build /build/.env . +COPY --from=build /build/swagger.yaml . + + +# Run the binary program produced by `go install` +CMD ["./go-api"] + diff --git a/ARANGO_API/go.mod b/ARANGO_API/go.mod new file mode 100644 index 000000000..84f8dc725 --- /dev/null +++ b/ARANGO_API/go.mod @@ -0,0 +1,51 @@ +module go-api + +go 1.20 + +require ( + github.com/arangodb/go-driver v1.6.0 // indirect + github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.9.1 // indirect + github.com/go-openapi/analysis v0.21.4 // indirect + github.com/go-openapi/errors v0.20.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/loads v0.21.2 // indirect + github.com/go-openapi/runtime v0.26.0 // indirect + github.com/go-openapi/spec v0.20.8 // indirect + github.com/go-openapi/strfmt v0.21.7 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/validate v0.22.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/oklog/ulid v1.3.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + go.mongodb.org/mongo-driver v1.11.3 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/ARANGO_API/go.sum b/ARANGO_API/go.sum new file mode 100644 index 000000000..eec00c320 --- /dev/null +++ b/ARANGO_API/go.sum @@ -0,0 +1,255 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/arangodb/go-driver v1.6.0 h1:NFWj/idqXZxhFVueihMSI2R9NotNIsgvNfM/xmpekb4= +github.com/arangodb/go-driver v1.6.0/go.mod h1:HQmdGkvNMVBTE3SIPSQ8T/ZddC6iwNsfMR+dDJQxIsI= +github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e h1:Xg+hGrY2LcQBbxd0ZFdbGSyRKTYMZCfBbw/pMJFOk1g= +github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e/go.mod h1:mq7Shfa/CaixoDxiyAAc5jZ6CVBAyPaNQCGS7mkj4Ho= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +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/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= +github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= +github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= +github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= +github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= +github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= +github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= +github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= +github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= +github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= +github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= +github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= +github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.2/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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +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.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +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= +go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= +go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +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-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.5/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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.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-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/ARANGO_API/handlers/connection.go b/ARANGO_API/handlers/connection.go new file mode 100644 index 000000000..223406ba6 --- /dev/null +++ b/ARANGO_API/handlers/connection.go @@ -0,0 +1,120 @@ +package handlers + +import ( + "net/http" + + "go-api/database" + "github.com/gin-gonic/gin" +) + +// swagger:operation GET /Connections Connections Connection +// Get Connection list +// +// --- +// parameters: +// - name: _key +// in: query +// description: Key of connection +// required: false +// type: string +// - name: _from +// in: query +// description: From witch device +// required: false +// type: string +// - name: _to +// in: query +// description: To witch device +// required: false +// type: string +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessConResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func GetConnection(c *gin.Context) { + + conn, err := database.GetAll(c,"links") + if err != nil { + c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) + return + } + if len(conn) == 0 { + c.IndentedJSON(http.StatusNotFound, gin.H{"message": "no connection found"}) + return + } + c.IndentedJSON(http.StatusOK, conn) +} + + +// swagger:operation POST /Connections Connections CreateConnection +// Create new Connection +// +// --- +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessConResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func PostConnection(c *gin.Context) { + + var newConn map[string]string + + // Call BindJSON to bind the received JSON to + if err := c.BindJSON(&newConn); err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + + result,err := database.InsertConnection(c, newConn); + if err != nil { + c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) + return + } + c.IndentedJSON(http.StatusCreated, result) +} + +// swagger:operation DELETE /Connections/{connection} Connections DeleteConnection +// Delete Connection by key +// +// --- +// parameters: +// - name: connection +// in: path +// description: connection looking for +// required: true +// type: string +// +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func DeleteConnection(c *gin.Context){ + key := c.Param("key") + + conn, err := database.Delete(c,key,"links") + if err != nil { + c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) + return + } + c.IndentedJSON(http.StatusOK, conn) +} \ No newline at end of file diff --git a/ARANGO_API/handlers/database.go b/ARANGO_API/handlers/database.go new file mode 100644 index 000000000..f83194a16 --- /dev/null +++ b/ARANGO_API/handlers/database.go @@ -0,0 +1,95 @@ +package handlers + +import ( + "net/http" + + "go-api/database" + "go-api/models" + + "github.com/gin-gonic/gin" +) + + +// swagger:operation GET /Database Database Database +// Get database name +// +// --- +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" + +func GetBDD(c *gin.Context){ + db, err := database.GetDBConn(c) + if err != nil { + c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) + return + } + addr,ok:= c.Value("addr").(*string) + if !ok { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Fail to get database hostname"}) + return + } + + info ,_ := (*db).Info(nil) + + c.IndentedJSON(http.StatusOK, gin.H{"message": "Connected to "+(*addr)+" on database: "+info.Name}) + + +} + +// swagger:operation POST /Database Database ConnectBDD +// Connect to new bdd +// +// --- +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func ConnectBDD(c *gin.Context){ + db, err := database.GetDBConn(c) + if err != nil && err.StatusCode != 404 { + c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) + return + } + + addr,ok:= c.Value("addr").(*string) + if !ok { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Fail to get database hostname"}) + return + } + + var DBInfo models.DatabaseInfo + if err := c.BindJSON(&DBInfo); err != nil { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": err.Error()}) + return + } + + newDB, err := database.ConnectToArrengo(DBInfo.Host,DBInfo.Database,DBInfo.User,DBInfo.Password) + + if err != nil { + c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) + return + } + + (*db) = newDB + (*addr) = DBInfo.Host + info ,_ := (*db).Info(nil) + + c.IndentedJSON(http.StatusOK, gin.H{"message": "Connected to "+(*addr)+" on database: "+info.Name}) + +} \ No newline at end of file diff --git a/ARANGO_API/handlers/devices.go b/ARANGO_API/handlers/devices.go new file mode 100644 index 000000000..ca59a52db --- /dev/null +++ b/ARANGO_API/handlers/devices.go @@ -0,0 +1,138 @@ +package handlers + +import ( + "net/http" + + "go-api/database" + + "github.com/gin-gonic/gin" +) + +// swagger:operation GET /Devices Devices Devices +// Get Devices list +// +// --- +// parameters: +// - name: _key +// in: query +// description: Key of device +// required: false +// type: string +// - name: _name +// in: query +// description: Name of device +// required: false +// type: string +// - name: group_name +// in: query +// description: Group_name of device +// required: false +// type: string +// - name: serial +// in: query +// description: Serial number of device +// required: false +// type: string +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" + +func GetDevices(c *gin.Context) { + + devices, err := database.GetAll(c,"devices") + if err != nil { + c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) + return + } + if len(devices) == 0 { + c.IndentedJSON(http.StatusNotFound, gin.H{"message": "Devices not found"}) + return + } + c.IndentedJSON(http.StatusOK, devices) +} + +// swagger:operation POST /Devices Devices CreateDevices +// Create new Devices +// +// --- +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func PostDevices(c *gin.Context) { + + var newDevices map[string]string + + // Call BindJSON to bind the received JSON to + if err := c.BindJSON(&newDevices); err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + + //Checking minimal configuration + if newDevices["_name"] == "" { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message":"Device needs Name"}) + return + } + if newDevices["created"] == ""{ + c.IndentedJSON(http.StatusBadRequest, gin.H{"message":"Device needs created date"}) + return + } + if newDevices["group_name"] == ""{ + c.IndentedJSON(http.StatusBadRequest, gin.H{"message":"Device needs roup Name"}) + return + } + result,err := database.InsertDevices(c, newDevices); + if err != nil { + c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) + return + } + c.IndentedJSON(http.StatusCreated, result) +} +// swagger:operation DELETE /Devices/{device} Devices DeleteDevices +// Delete Devices by key +// +// --- +// parameters: +// - name: device +// in: path +// description: device looking for +// required: true +// type: string +// +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func DeleteDevice(c *gin.Context){ + key := c.Param("key") + + devices, err := database.Delete(c,key,"devices") + if err != nil { + c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) + return + } + c.IndentedJSON(http.StatusOK, devices) +} diff --git a/ARANGO_API/handlers/swagger.go b/ARANGO_API/handlers/swagger.go new file mode 100644 index 000000000..9ef47db78 --- /dev/null +++ b/ARANGO_API/handlers/swagger.go @@ -0,0 +1,19 @@ +package handlers + +import( + "net/http" + "github.com/go-openapi/runtime/middleware" + "github.com/gorilla/mux" +) + +func SwaggerHandler() *mux.Router{ + pr := mux.NewRouter() + + pr.Handle("/swagger.yaml", http.FileServer(http.Dir("./"))) + opts := middleware.SwaggerUIOpts{SpecURL: "swagger.yaml"} + sh := middleware.SwaggerUI(opts, nil) + pr.Handle("/docs", sh) + + return pr + +} \ No newline at end of file diff --git a/ARANGO_API/main.go b/ARANGO_API/main.go new file mode 100644 index 000000000..78a447292 --- /dev/null +++ b/ARANGO_API/main.go @@ -0,0 +1,43 @@ +// Arrango API: +// version: 1.0.0 +// title: Awsome API +// Schemes: http, https +// Host: +// BasePath: /api/v1 +// Consumes: +// - application/json +// Produces: +// - application/json +// SecurityDefinitions: +// Bearer: +// type: apiKey +// name: Authorization +// in: header +// swagger:meta +package main + +import ( + "fmt" + "os" + "go-api/services" + "go-api/database" +) + +func main() { + addr := os.Getenv("ARRANGO_URL") + bdd := os.Getenv("ARRANGO_DATABASE") + user := os.Getenv("ARRANGO_USER") + password := os.Getenv("ARRANGO_PASSWORD") + + + db, err := database.ConnectToArrengo(addr,bdd, user, password) + if err != nil { + fmt.Println("Error connecting to database: ", err.Message) + return + } + + database.CreateCollection(db, "devices") + + router := services.InitRouter(db,addr) + router.Run(":8080") +} diff --git a/ARANGO_API/models/connections.go b/ARANGO_API/models/connections.go new file mode 100644 index 000000000..8c33751a6 --- /dev/null +++ b/ARANGO_API/models/connections.go @@ -0,0 +1,43 @@ +package models + +// swagger:model Connection +type Connection struct { + + // Primary key of device + // in: _key + // read only: true + Key string `json:"_key"` + + // from Device + // in: _from + // example: devices/* + From string `json:"_from"` + + // To device + // in: _to + // example: devices/* + To string `json:"_to"` + + // Type of connection + // in: type + // example: parent of (between partens) + Type string `json:"type"` + + // Date of connection's creation + // in: created + // example: 2016-04-22 + Created string `json:"created"` + + // Date of connection's expiration + // in: expired + // example: 3000-01-01 + Expired string `json:"expired"` + +} + +// swagger:model SuccessConResponse +type SuccessConResponse struct { + // Success + // in : array + Connections []Connection +} \ No newline at end of file diff --git a/ARANGO_API/models/devices.go b/ARANGO_API/models/devices.go new file mode 100644 index 000000000..568549d6e --- /dev/null +++ b/ARANGO_API/models/devices.go @@ -0,0 +1,61 @@ +package models + +// swagger:model Devices +type Devices struct { + + // Primary key of device + // in: _key + // read only: true + Key string `json:"_key"` + // name of Devices + // in: _name + // example: storage_bay + Name string `json:"_name"` + // group_name of Devices + // in: group_name + // example: GS00OPSAN06 + GroupName string `json:"group_name"` + // category of Devices + // in: category + // example: port + Category string `json:"category"` + // sp_name of Devices + // in: sp_name + // example: sp_b + SpName string `json:"sp_name"` + + // sp_port_id of Devices + // in: sp_port_id + // example: 0 + SpPortId string `json:"sp_port_id"` + + // hba_device_name of Devices + // in: hba_device_name + // example: nsa.* + HbaDeviceName string `json:"hba_device_name"` + + // storage_group_name of Devices + // in: storage_group_name + // example: storage + StorageGroupName string `json:"storage_group_name"` + + // Date of device's creation + // in: created + // example: 2016-04-22 + Created string `json:"created"` + + // Date of device's expiration + // in: expired + // example: 3000-01-01 + Expired string `json:"expired"` + +} + +// swagger:model SuccessResponse +type SuccessResponse struct { + // Success + // in : array + Devices []Devices +} + + diff --git a/ARANGO_API/models/http.go b/ARANGO_API/models/http.go new file mode 100644 index 000000000..94eb98c4c --- /dev/null +++ b/ARANGO_API/models/http.go @@ -0,0 +1,54 @@ +package models + +// swagger:model ErrorResponse +type ErrorResponse struct { + // Error Response Message + // in: message + Message string `json:"message"` +} + +// swagger:parameters CreateDevices +type ReqDevicesBody struct { + // in: body + Body Devices `json:"body"` +} + +// swagger:parameters CreateConnection +type ReqConnBody struct { + // in: body + Body Connection `json:"body"` +} + +type ErrorMessage struct { + + StatusCode int `json:"statuscode"` + Message string `json:"message"` +} +// swagger:model DatabaseInfo +type DatabaseInfo struct { + // Host url of database + // in: host + // example: http://localhost:8529 + Host string `json:"host"` + + // Database name + // in: database + // example: _system + Database string `json:"database"` + + // User of database + // in: user + // example: root + User string `json:"user"` + + // Password of the user + // in: password + // example: password + Password string `json:"password"` +} + +// swagger:parameters ConnectBDD +type ReqBDDBody struct { + // in: body + Body DatabaseInfo `json:"body"` +} \ No newline at end of file diff --git a/ARANGO_API/services/router.go b/ARANGO_API/services/router.go new file mode 100644 index 000000000..c713ffc3d --- /dev/null +++ b/ARANGO_API/services/router.go @@ -0,0 +1,47 @@ +package services + +import ( + "go-api/handlers" + "os" + driver "github.com/arangodb/go-driver" + "github.com/gin-gonic/gin" +) + + +func DBMiddleware(db driver.Database,addr string) gin.HandlerFunc { + + return func(c *gin.Context) { + c.Set("database", &db) + c.Set("addr", &addr) + c.Next() + } +} + +func InitRouter(db driver.Database,addr string) *gin.Engine { + env := os.Getenv("ENV") + if env =="production"{ + gin.SetMode(gin.ReleaseMode) + } + + router := gin.Default() + + + + router.Use(DBMiddleware(db,addr)) + + router.GET("/api/v1//Devices", handlers.GetDevices) + router.POST("/api/v1//Devices", handlers.PostDevices) + router.DELETE("/api/v1//Devices/:key", handlers.DeleteDevice) + + router.GET("/api/v1//Connections", handlers.GetConnection) + router.POST("/api/v1//Connections", handlers.PostConnection) + router.DELETE("/api/v1//Connections/:key", handlers.DeleteConnection) + + router.GET("/api/v1/Database", handlers.GetBDD) + router.POST("/api/v1/Database", handlers.ConnectBDD) + + swagger := handlers.SwaggerHandler() + router.Use(gin.WrapH(swagger)) + + return router +} diff --git a/ARANGO_API/swagger.yaml b/ARANGO_API/swagger.yaml new file mode 100644 index 000000000..d06573ea3 --- /dev/null +++ b/ARANGO_API/swagger.yaml @@ -0,0 +1,396 @@ +basePath: /api/v1 +consumes: + - application/json +definitions: + Connection: + properties: + _from: + description: |- + from Device + in: _from + example: devices/* + type: string + x-go-name: From + _key: + description: |- + Primary key of device + in: _key + readOnly: true + type: string + x-go-name: Key + _to: + description: |- + To device + in: _to + example: devices/* + type: string + x-go-name: To + created: + description: |- + Date of connection's creation + in: created + example: "2016-04-22" + type: string + x-go-name: Created + expired: + description: |- + Date of connection's expiration + in: expired + example: "3000-01-01" + type: string + x-go-name: Expired + type: + description: |- + Type of connection + in: type + example: parent of (between partens) + type: string + x-go-name: Type + type: object + x-go-package: go-api/models + DatabaseInfo: + properties: + database: + description: |- + Database name + in: database + example: _system + type: string + x-go-name: Database + host: + description: |- + Host url of database + in: host + example: http://localhost:8529 + type: string + x-go-name: Host + password: + description: |- + Password of the user + in: password + example: password + type: string + x-go-name: Password + user: + description: |- + User of database + in: user + example: root + type: string + x-go-name: User + type: object + x-go-package: go-api/models + Devices: + properties: + _key: + description: |- + Primary key of device + in: _key + readOnly: true + type: string + x-go-name: Key + _name: + description: |- + name of Devices + in: _name + example: storage_bay + type: string + x-go-name: Name + category: + description: |- + category of Devices + in: category + example: port + type: string + x-go-name: Category + created: + description: |- + Date of device's creation + in: created + example: "2016-04-22" + type: string + x-go-name: Created + expired: + description: |- + Date of device's expiration + in: expired + example: "3000-01-01" + type: string + x-go-name: Expired + group_name: + description: |- + group_name of Devices + in: group_name + example: GS00OPSAN06 + type: string + x-go-name: GroupName + hba_device_name: + description: |- + hba_device_name of Devices + in: hba_device_name + example: nsa.* + type: string + x-go-name: HbaDeviceName + sp_name: + description: |- + sp_name of Devices + in: sp_name + example: sp_b + type: string + x-go-name: SpName + sp_port_id: + description: |- + sp_port_id of Devices + in: sp_port_id + example: "0" + type: string + x-go-name: SpPortId + storage_group_name: + description: |- + storage_group_name of Devices + in: storage_group_name + example: storage + type: string + x-go-name: StorageGroupName + type: object + x-go-package: go-api/models + ErrorResponse: + properties: + message: + description: |- + Error Response Message + in: message + type: string + x-go-name: Message + type: object + x-go-package: go-api/models + SuccessConResponse: + properties: + Connections: + description: |- + Success + in : array + items: + $ref: '#/definitions/Connection' + type: array + type: object + x-go-package: go-api/models + SuccessResponse: + properties: + Devices: + description: |- + Success + in : array + items: + $ref: '#/definitions/Devices' + type: array + type: object + x-go-package: go-api/models +info: + title: 'Arrango API:' + version: 1.0.0 +paths: + /Connections: + get: + description: Get Connection list + operationId: Connection + parameters: + - description: Key of connection + in: query + name: _key + type: string + - description: From witch device + in: query + name: _from + type: string + - description: To witch device + in: query + name: _to + type: string + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/SuccessConResponse' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + tags: + - Connections + post: + description: Create new Connection + operationId: CreateConnection + parameters: + - in: body + name: body + schema: + $ref: '#/definitions/Connection' + x-go-name: Body + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/SuccessConResponse' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + tags: + - Connections + /Connections/{connection}: + delete: + description: Delete Connection by key + operationId: DeleteConnection + parameters: + - description: connection looking for + in: path + name: connection + required: true + type: string + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/SuccessResponse' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + tags: + - Connections + /Database: + get: + description: Get database name + operationId: Database + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/ErrorResponse' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + tags: + - Database + post: + description: Connect to new bdd + operationId: ConnectBDD + parameters: + - in: body + name: body + schema: + $ref: '#/definitions/DatabaseInfo' + x-go-name: Body + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/ErrorResponse' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + tags: + - Database + /Devices: + get: + description: Get Devices list + operationId: Devices + parameters: + - description: Key of device + in: query + name: _key + type: string + - description: Name of device + in: query + name: _name + type: string + - description: Group_name of device + in: query + name: group_name + type: string + - description: Serial number of device + in: query + name: serial + type: string + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/SuccessResponse' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + tags: + - Devices + post: + description: Create new Devices + operationId: CreateDevices + parameters: + - in: body + name: body + schema: + $ref: '#/definitions/Devices' + x-go-name: Body + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/SuccessResponse' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + tags: + - Devices + /Devices/{device}: + delete: + description: Delete Devices by key + operationId: DeleteDevices + parameters: + - description: device looking for + in: path + name: device + required: true + type: string + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/SuccessResponse' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + tags: + - Devices +produces: + - application/json +schemes: + - http + - https +securityDefinitions: + Bearer: + in: header + name: Authorization + type: apiKey +swagger: "2.0" From adc8c33f382ef3df260819992e04b9591d03dbfb Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Thu, 3 Aug 2023 17:47:19 +0200 Subject: [PATCH 02/35] feat(arango): add arango api to docker compose --- ARANGO_API/dockerfile | 8 +++---- deploy/docker/.env | 8 +++++++ deploy/docker/docker-compose.yml | 41 +++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/ARANGO_API/dockerfile b/ARANGO_API/dockerfile index b17466484..a3fd31508 100644 --- a/ARANGO_API/dockerfile +++ b/ARANGO_API/dockerfile @@ -4,13 +4,12 @@ FROM golang:1.18.2-alpine3.16 AS build WORKDIR /build # We want to populate the module cache based on the go.{mod,sum} files. -COPY go.mod . -COPY go.sum . +COPY ARANGO_API/go.mod . +COPY ARANGO_API/go.sum . RUN go mod download -COPY . . -RUN cp env .env +COPY ARANGO_API/. . # Build the Go app @@ -22,7 +21,6 @@ FROM alpine:3.16 WORKDIR /bin COPY --from=build /build/go-api . -COPY --from=build /build/.env . COPY --from=build /build/swagger.yaml . diff --git a/deploy/docker/.env b/deploy/docker/.env index 864f759b2..b47b0fe6d 100644 --- a/deploy/docker/.env +++ b/deploy/docker/.env @@ -9,3 +9,11 @@ CUSTOMER_API_PASSWORD=pass123 API_EXTERNALURL=localhost APP_ASSETS_DIR=../../APP/ogree_app/assets/custom IMAGE_TAG=main + +#ARANGODB_ +ARANGO_API_BUILD_DIR=ARANGO_API +ARANGO_PASS=ogree +ARANGO_USER=root +ARANGO_DB="_system" +ARANGO_PORT=8529 + diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 0db00004b..d751501b3 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -63,5 +63,44 @@ services: - ogree_api restart: on-failure:10 + + + arango_db: + image: arangodb/arangodb:3.11.2 + container_name: ${COMPOSE_PROJECT_NAME}_arango_db + environment: + - ARANGO_ROOT_PASSWORD=${ARANGO_PASS} + volumes: + - arangodb-persist:/var/lib/arangodb3 + ports: + - ${ARANGO_PORT}:8529 + restart: on-failure:10 + + + arrango_api: + build: + context: ${CORE_DIR} + dockerfile: ${ARANGO_API_BUILD_DIR}/Dockerfile + image: arango-api:${IMAGE_TAG} + restart: always + container_name: ${COMPOSE_PROJECT_NAME}_arango_api + environment: + - ENV=production + - ARRANGO_URL=http://${COMPOSE_PROJECT_NAME}_arango_db:${ARANGO_PORT} + - ARRANGO_DATABASE=${ARANGO_DB} + - ARRANGO_USER=${ARANGO_USER} + - ARRANGO_PASSWORD=${ARANGO_PASS} + ports: + - 8080:8080 + healthcheck: + test: ["CMD", "curl","-f","http://${COMPOSE_PROJECT_NAME}_arango_db:5829/_api/version"] + timeout: 30s + interval: 1m + retries: 3 + volumes: - db: \ No newline at end of file + db: + arangodb-persist: + external: true + + From c7e7f4752f21509a890d14b9a71fe975e7c56649 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Fri, 4 Aug 2023 10:02:05 +0200 Subject: [PATCH 03/35] fix(port): arango_api_port has a variable --- deploy/docker/.env | 1 + deploy/docker/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/deploy/docker/.env b/deploy/docker/.env index b47b0fe6d..0c67d1b27 100644 --- a/deploy/docker/.env +++ b/deploy/docker/.env @@ -12,6 +12,7 @@ IMAGE_TAG=main #ARANGODB_ ARANGO_API_BUILD_DIR=ARANGO_API +ARANGO_API_PORT=8080 ARANGO_PASS=ogree ARANGO_USER=root ARANGO_DB="_system" diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index d751501b3..22bf9e18d 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -91,7 +91,7 @@ services: - ARRANGO_USER=${ARANGO_USER} - ARRANGO_PASSWORD=${ARANGO_PASS} ports: - - 8080:8080 + - ${ARANGO_API_PORT}:8080 healthcheck: test: ["CMD", "curl","-f","http://${COMPOSE_PROJECT_NAME}_arango_db:5829/_api/version"] timeout: 30s From c0c506a18ac8fd0af6197e313c550b03fa2d4597 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Fri, 4 Aug 2023 10:04:14 +0200 Subject: [PATCH 04/35] fix(package): rename go-api to arango-api --- .gitignore | 4 +- ARANGO_API/database/common.go | 79 +++++++++++++++--------------- ARANGO_API/database/connection.go | 33 +++++++------ ARANGO_API/database/devices.go | 54 ++++++++++----------- ARANGO_API/dockerfile | 6 +-- ARANGO_API/go.mod | 2 +- ARANGO_API/handlers/connection.go | 80 ++++++++++++++++--------------- ARANGO_API/handlers/database.go | 55 +++++++++++---------- ARANGO_API/handlers/devices.go | 65 +++++++++++++------------ ARANGO_API/main.go | 12 ++--- ARANGO_API/services/router.go | 16 +++---- ARANGO_API/swagger.yaml | 12 ++--- deploy/docker/docker-compose.yml | 8 ++-- 13 files changed, 212 insertions(+), 214 deletions(-) diff --git a/.gitignore b/.gitignore index 796caa48e..df86fe1e2 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,5 @@ deploy/docker/*.env deploy/docker/app-deploy #ARANGO_API Ignore -ARANGO_API/go-api -ARANGO_API/env +ARANGO_API/arango-api +ARANGO_API/*env diff --git a/ARANGO_API/database/common.go b/ARANGO_API/database/common.go index 3e22450bc..ac8be87b1 100644 --- a/ARANGO_API/database/common.go +++ b/ARANGO_API/database/common.go @@ -1,57 +1,55 @@ package database + import ( - h "net/http" - "go-api/models" + "arango-api/models" "encoding/json" - "github.com/gin-gonic/gin" - "github.com/arangodb/go-driver/http" + h "net/http" + driver "github.com/arangodb/go-driver" + "github.com/arangodb/go-driver/http" + "github.com/gin-gonic/gin" ) - - - -func GetDBConn(c *gin.Context) (*driver.Database,*models.ErrorMessage) { - dbConn,ok:= c.Value("database").(*driver.Database) +func GetDBConn(c *gin.Context) (*driver.Database, *models.ErrorMessage) { + dbConn, ok := c.Value("database").(*driver.Database) //dbConn, ok := c.MustGet("database").(driver.Database) if !ok { - return nil, &models.ErrorMessage{StatusCode: h.StatusInternalServerError,Message:"Failed to get database"} + return nil, &models.ErrorMessage{StatusCode: h.StatusInternalServerError, Message: "Failed to get database"} } if *dbConn == nil { - return nil, &models.ErrorMessage{StatusCode: h.StatusNotFound,Message:"Failed to get database"} + return nil, &models.ErrorMessage{StatusCode: h.StatusNotFound, Message: "Failed to get database"} } return dbConn, nil } -func ParseToString(obj interface{}) (string,*models.ErrorMessage) { - - asJson,err := json.Marshal(obj) - if err != nil{ - return "",&models.ErrorMessage{StatusCode: h.StatusInternalServerError,Message:"Failed to parse query string"} +func ParseToString(obj interface{}) (string, *models.ErrorMessage) { + + asJson, err := json.Marshal(obj) + if err != nil { + return "", &models.ErrorMessage{StatusCode: h.StatusInternalServerError, Message: "Failed to parse query string"} } return string(asJson), nil - } func ExecQuerry(db driver.Database, query string) ([]interface{}, *models.ErrorMessage) { - + var result []interface{} cursor, err := db.Query(nil, query, nil) if err != nil { - return result,&models.ErrorMessage{StatusCode: h.StatusInternalServerError,Message: err.Error()} + return result, &models.ErrorMessage{StatusCode: h.StatusInternalServerError, Message: err.Error()} } defer cursor.Close() for { var doc interface{} - _ ,err = cursor.ReadDocument(nil, &doc) + _, err = cursor.ReadDocument(nil, &doc) if driver.IsNoMoreDocuments(err) { break } else if err != nil { - return result, &models.ErrorMessage{StatusCode: h.StatusInternalServerError,Message: err.Error()} + return result, &models.ErrorMessage{StatusCode: h.StatusInternalServerError, Message: err.Error()} } else { result = append(result, doc) } @@ -60,45 +58,44 @@ func ExecQuerry(db driver.Database, query string) ([]interface{}, *models.ErrorM } -func GetAll(c *gin.Context,col string) ([]interface{},*models.ErrorMessage){ +func GetAll(c *gin.Context, col string) ([]interface{}, *models.ErrorMessage) { db, err := GetDBConn(c) if err != nil { return nil, err } values := c.Request.URL.Query() - querystring := "FOR doc IN "+col + querystring := "FOR doc IN " + col - for key,value := range values{ - querystring += " FILTER doc."+key+" == \""+value[0]+"\" " + for key, value := range values { + querystring += " FILTER doc." + key + " == \"" + value[0] + "\" " } querystring += " RETURN doc" - result, err := ExecQuerry(*db, querystring); + result, err := ExecQuerry(*db, querystring) if err != nil { return nil, err } return result, nil } - -func Delete(c *gin.Context, key, col string) ([]interface{},*models.ErrorMessage) { +func Delete(c *gin.Context, key, col string) ([]interface{}, *models.ErrorMessage) { db, err := GetDBConn(c) if err != nil { return nil, err } - querystring := "FOR doc IN "+col+" FILTER doc.`_key`== \""+key+"\" REMOVE doc IN "+col + querystring := "FOR doc IN " + col + " FILTER doc.`_key`== \"" + key + "\" REMOVE doc IN " + col - result, err := ExecQuerry(*db, querystring); + result, err := ExecQuerry(*db, querystring) if err != nil { return nil, err } - return result,nil + return result, nil } -func Update(c *gin.Context, doc interface{},key, col string) ([]interface{},*models.ErrorMessage) { +func Update(c *gin.Context, doc interface{}, key, col string) ([]interface{}, *models.ErrorMessage) { db, err := GetDBConn(c) if err != nil { return nil, err @@ -106,15 +103,15 @@ func Update(c *gin.Context, doc interface{},key, col string) ([]interface{},*mod docStr, err := ParseToString(doc) if err != nil { - return nil, err - } - querystring := "UPDATE \""+key+"\" WITH "+docStr+" IN "+col+" RETURN "+key + return nil, err + } + querystring := "UPDATE \"" + key + "\" WITH " + docStr + " IN " + col + " RETURN " + key - result, err := ExecQuerry(*db, querystring); + result, err := ExecQuerry(*db, querystring) if err != nil { return nil, err } - return result,nil + return result, nil } func ConnectToArrengo(addr, database, user, password string) (driver.Database, *models.ErrorMessage) { @@ -123,7 +120,7 @@ func ConnectToArrengo(addr, database, user, password string) (driver.Database, * Endpoints: []string{addr}, }) if err != nil { - return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest,Message: err.Error()} + return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest, Message: err.Error()} } client, err := driver.NewClient(driver.ClientConfig{ @@ -131,12 +128,12 @@ func ConnectToArrengo(addr, database, user, password string) (driver.Database, * Authentication: driver.BasicAuthentication(user, password), }) if err != nil { - return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest,Message: err.Error()} + return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest, Message: err.Error()} } db, err := client.Database(nil, database) if err != nil { - return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest,Message: err.Error()} + return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest, Message: err.Error()} } return db, nil @@ -156,4 +153,4 @@ func CreateCollection(db driver.Database, collectionName string) (driver.Collect return col, nil -} \ No newline at end of file +} diff --git a/ARANGO_API/database/connection.go b/ARANGO_API/database/connection.go index 41457e8ae..fa19a9a7c 100644 --- a/ARANGO_API/database/connection.go +++ b/ARANGO_API/database/connection.go @@ -1,11 +1,11 @@ package database import ( -// driver "github.com/arangodb/go-driver" - "github.com/gin-gonic/gin" - "go-api/models" + // driver "github.com/arangodb/go-driver" + "arango-api/models" "net/http" + "github.com/gin-gonic/gin" ) func InsertConnection(c *gin.Context, conn map[string]string) ([]interface{}, *models.ErrorMessage) { @@ -15,31 +15,30 @@ func InsertConnection(c *gin.Context, conn map[string]string) ([]interface{}, *m } // check if devices existed - existed,err := DeviceExistedById(*db, conn["_from"]) + existed, err := DeviceExistedById(*db, conn["_from"]) if err != nil { return nil, err } - if !existed{ - return nil, &models.ErrorMessage{StatusCode: http.StatusNotFound,Message:"Device "+conn["_from"]+" not found"} + if !existed { + return nil, &models.ErrorMessage{StatusCode: http.StatusNotFound, Message: "Device " + conn["_from"] + " not found"} } - existed,err = DeviceExistedById(*db, conn["_to"]) + existed, err = DeviceExistedById(*db, conn["_to"]) if err != nil { return nil, err } - if !existed{ - return nil, &models.ErrorMessage{StatusCode: http.StatusNotFound,Message:"Device "+conn["_to"]+" not found"} + if !existed { + return nil, &models.ErrorMessage{StatusCode: http.StatusNotFound, Message: "Device " + conn["_to"] + " not found"} } - connStr,err := ParseToString(conn) + connStr, err := ParseToString(conn) - if err != nil { - return nil, err - } - querystring := "INSERT "+connStr+" INTO links RETURN NEW" + return nil, err + } + querystring := "INSERT " + connStr + " INTO links RETURN NEW" - result, err := ExecQuerry(*db, querystring); + result, err := ExecQuerry(*db, querystring) if err != nil { return nil, err } - return result,nil -} \ No newline at end of file + return result, nil +} diff --git a/ARANGO_API/database/devices.go b/ARANGO_API/database/devices.go index b2bd83d56..8430968a5 100644 --- a/ARANGO_API/database/devices.go +++ b/ARANGO_API/database/devices.go @@ -1,45 +1,44 @@ package database import ( - driver "github.com/arangodb/go-driver" - "github.com/gin-gonic/gin" - "go-api/models" + "arango-api/models" "net/http" + driver "github.com/arangodb/go-driver" + "github.com/gin-gonic/gin" ) - -func DeviceExistedById(db driver.Database,id string) (bool, *models.ErrorMessage) { +func DeviceExistedById(db driver.Database, id string) (bool, *models.ErrorMessage) { querystring := "FOR devices IN devices " - querystring += "FILTER devices.`_id` == \""+id+"\" " + querystring += "FILTER devices.`_id` == \"" + id + "\" " querystring += "RETURN devices" - - created, err := ExecQuerry(db, querystring); + + created, err := ExecQuerry(db, querystring) if err != nil { return false, err } - if len(created)!=0{ + if len(created) != 0 { return true, nil } - return false,nil + return false, nil } -func DeviceExisted(db driver.Database,device map[string]string) (bool, *models.ErrorMessage) { +func DeviceExisted(db driver.Database, device map[string]string) (bool, *models.ErrorMessage) { querystring := "FOR devices IN devices " - querystring += "FILTER devices.`_name` == \""+device["_name"]+"\" " - querystring += "&& devices.`group_name` == \""+ device["group_name"]+"\" " - querystring += "&& devices.`created` == \""+ device["created"]+"\" " + querystring += "FILTER devices.`_name` == \"" + device["_name"] + "\" " + querystring += "&& devices.`group_name` == \"" + device["group_name"] + "\" " + querystring += "&& devices.`created` == \"" + device["created"] + "\" " querystring += "RETURN devices" - - created, err := ExecQuerry(db, querystring); + + created, err := ExecQuerry(db, querystring) if err != nil { return false, err } - if len(created)!=0{ + if len(created) != 0 { return true, nil } - return false,nil + return false, nil } func InsertDevices(c *gin.Context, device map[string]string) ([]interface{}, *models.ErrorMessage) { @@ -49,24 +48,23 @@ func InsertDevices(c *gin.Context, device map[string]string) ([]interface{}, *mo } // check if devices existed - existed,err := DeviceExisted(*db, device) + existed, err := DeviceExisted(*db, device) if err != nil { return nil, err } - if existed{ - return nil,&models.ErrorMessage{StatusCode: http.StatusFound,Message:"Device already existed"} + if existed { + return nil, &models.ErrorMessage{StatusCode: http.StatusFound, Message: "Device already existed"} } - deviceStr,err := ParseToString(device) + deviceStr, err := ParseToString(device) - if err != nil { - return nil, err - } - querystring := "INSERT "+deviceStr+" INTO devices RETURN NEW" + return nil, err + } + querystring := "INSERT " + deviceStr + " INTO devices RETURN NEW" - result, err := ExecQuerry(*db, querystring); + result, err := ExecQuerry(*db, querystring) if err != nil { return nil, err } - return result,nil + return result, nil } diff --git a/ARANGO_API/dockerfile b/ARANGO_API/dockerfile index a3fd31508..92e0247d5 100644 --- a/ARANGO_API/dockerfile +++ b/ARANGO_API/dockerfile @@ -13,17 +13,17 @@ COPY ARANGO_API/. . # Build the Go app -RUN CGO_ENABLED=0 GOOS=linux go build -a -o go-api -ldflags "-X main.version=${VERSION} -X 'main.build=$(date)'" . +RUN CGO_ENABLED=0 GOOS=linux go build -a -o arango-api -ldflags "-X main.version=${VERSION} -X 'main.build=$(date)'" . # Start fresh from a smaller image FROM alpine:3.16 WORKDIR /bin -COPY --from=build /build/go-api . +COPY --from=build /build/arango-api . COPY --from=build /build/swagger.yaml . # Run the binary program produced by `go install` -CMD ["./go-api"] +CMD ["./arango-api"] diff --git a/ARANGO_API/go.mod b/ARANGO_API/go.mod index 84f8dc725..b0adac32b 100644 --- a/ARANGO_API/go.mod +++ b/ARANGO_API/go.mod @@ -1,4 +1,4 @@ -module go-api +module arango-api go 1.20 diff --git a/ARANGO_API/handlers/connection.go b/ARANGO_API/handlers/connection.go index 223406ba6..6aa62bf02 100644 --- a/ARANGO_API/handlers/connection.go +++ b/ARANGO_API/handlers/connection.go @@ -3,7 +3,8 @@ package handlers import ( "net/http" - "go-api/database" + "arango-api/database" + "github.com/gin-gonic/gin" ) @@ -27,20 +28,22 @@ import ( // description: To witch device // required: false // type: string +// // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessConResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessConResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func GetConnection(c *gin.Context) { - conn, err := database.GetAll(c,"links") + conn, err := database.GetAll(c, "links") if err != nil { c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) return @@ -52,24 +55,24 @@ func GetConnection(c *gin.Context) { c.IndentedJSON(http.StatusOK, conn) } - // swagger:operation POST /Connections Connections CreateConnection // Create new Connection // // --- // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessConResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessConResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func PostConnection(c *gin.Context) { - + var newConn map[string]string // Call BindJSON to bind the received JSON to @@ -78,7 +81,7 @@ func PostConnection(c *gin.Context) { return } - result,err := database.InsertConnection(c, newConn); + result, err := database.InsertConnection(c, newConn) if err != nil { c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) return @@ -98,23 +101,24 @@ func PostConnection(c *gin.Context) { // type: string // // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -func DeleteConnection(c *gin.Context){ +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func DeleteConnection(c *gin.Context) { key := c.Param("key") - conn, err := database.Delete(c,key,"links") + conn, err := database.Delete(c, key, "links") if err != nil { c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) return } c.IndentedJSON(http.StatusOK, conn) -} \ No newline at end of file +} diff --git a/ARANGO_API/handlers/database.go b/ARANGO_API/handlers/database.go index f83194a16..97fa0aa22 100644 --- a/ARANGO_API/handlers/database.go +++ b/ARANGO_API/handlers/database.go @@ -3,13 +3,12 @@ package handlers import ( "net/http" - "go-api/database" - "go-api/models" + "arango-api/database" + "arango-api/models" "github.com/gin-gonic/gin" ) - // swagger:operation GET /Database Database Database // Get database name // @@ -26,22 +25,21 @@ import ( // items: // "$ref": "#/definitions/ErrorResponse" -func GetBDD(c *gin.Context){ +func GetBDD(c *gin.Context) { db, err := database.GetDBConn(c) if err != nil { c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) - return + return } - addr,ok:= c.Value("addr").(*string) + addr, ok := c.Value("addr").(*string) if !ok { c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Fail to get database hostname"}) return } - info ,_ := (*db).Info(nil) - - c.IndentedJSON(http.StatusOK, gin.H{"message": "Connected to "+(*addr)+" on database: "+info.Name}) + info, _ := (*db).Info(nil) + c.IndentedJSON(http.StatusOK, gin.H{"message": "Connected to " + (*addr) + " on database: " + info.Name}) } @@ -50,24 +48,25 @@ func GetBDD(c *gin.Context){ // // --- // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -func ConnectBDD(c *gin.Context){ +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func ConnectBDD(c *gin.Context) { db, err := database.GetDBConn(c) if err != nil && err.StatusCode != 404 { c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) - return + return } - - addr,ok:= c.Value("addr").(*string) + + addr, ok := c.Value("addr").(*string) if !ok { c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Fail to get database hostname"}) return @@ -78,8 +77,8 @@ func ConnectBDD(c *gin.Context){ c.IndentedJSON(http.StatusBadRequest, gin.H{"message": err.Error()}) return } - - newDB, err := database.ConnectToArrengo(DBInfo.Host,DBInfo.Database,DBInfo.User,DBInfo.Password) + + newDB, err := database.ConnectToArrengo(DBInfo.Host, DBInfo.Database, DBInfo.User, DBInfo.Password) if err != nil { c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) @@ -88,8 +87,8 @@ func ConnectBDD(c *gin.Context){ (*db) = newDB (*addr) = DBInfo.Host - info ,_ := (*db).Info(nil) + info, _ := (*db).Info(nil) - c.IndentedJSON(http.StatusOK, gin.H{"message": "Connected to "+(*addr)+" on database: "+info.Name}) + c.IndentedJSON(http.StatusOK, gin.H{"message": "Connected to " + (*addr) + " on database: " + info.Name}) -} \ No newline at end of file +} diff --git a/ARANGO_API/handlers/devices.go b/ARANGO_API/handlers/devices.go index ca59a52db..79f8158ee 100644 --- a/ARANGO_API/handlers/devices.go +++ b/ARANGO_API/handlers/devices.go @@ -3,7 +3,7 @@ package handlers import ( "net/http" - "go-api/database" + "arango-api/database" "github.com/gin-gonic/gin" ) @@ -47,7 +47,7 @@ import ( func GetDevices(c *gin.Context) { - devices, err := database.GetAll(c,"devices") + devices, err := database.GetAll(c, "devices") if err != nil { c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) return @@ -64,18 +64,19 @@ func GetDevices(c *gin.Context) { // // --- // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func PostDevices(c *gin.Context) { - + var newDevices map[string]string // Call BindJSON to bind the received JSON to @@ -86,24 +87,25 @@ func PostDevices(c *gin.Context) { //Checking minimal configuration if newDevices["_name"] == "" { - c.IndentedJSON(http.StatusBadRequest, gin.H{"message":"Device needs Name"}) + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Device needs Name"}) return } - if newDevices["created"] == ""{ - c.IndentedJSON(http.StatusBadRequest, gin.H{"message":"Device needs created date"}) + if newDevices["created"] == "" { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Device needs created date"}) return } - if newDevices["group_name"] == ""{ - c.IndentedJSON(http.StatusBadRequest, gin.H{"message":"Device needs roup Name"}) + if newDevices["group_name"] == "" { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": "Device needs roup Name"}) return } - result,err := database.InsertDevices(c, newDevices); + result, err := database.InsertDevices(c, newDevices) if err != nil { c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) return } c.IndentedJSON(http.StatusCreated, result) } + // swagger:operation DELETE /Devices/{device} Devices DeleteDevices // Delete Devices by key // @@ -116,20 +118,21 @@ func PostDevices(c *gin.Context) { // type: string // // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -func DeleteDevice(c *gin.Context){ +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func DeleteDevice(c *gin.Context) { key := c.Param("key") - devices, err := database.Delete(c,key,"devices") + devices, err := database.Delete(c, key, "devices") if err != nil { c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) return diff --git a/ARANGO_API/main.go b/ARANGO_API/main.go index 78a447292..c9d6bf51b 100644 --- a/ARANGO_API/main.go +++ b/ARANGO_API/main.go @@ -17,17 +17,17 @@ package main import ( + "arango-api/database" + "arango-api/services" "fmt" "os" - "go-api/services" - "go-api/database" ) func main() { - addr := os.Getenv("ARRANGO_URL") - bdd := os.Getenv("ARRANGO_DATABASE") - user := os.Getenv("ARRANGO_USER") - password := os.Getenv("ARRANGO_PASSWORD") + addr := os.Getenv("ARANGO_URL") + bdd := os.Getenv("ARANGO_DATABASE") + user := os.Getenv("ARANGO_USER") + password := os.Getenv("ARANGO_PASSWORD") db, err := database.ConnectToArrengo(addr,bdd, user, password) diff --git a/ARANGO_API/services/router.go b/ARANGO_API/services/router.go index c713ffc3d..8233ba7f9 100644 --- a/ARANGO_API/services/router.go +++ b/ARANGO_API/services/router.go @@ -1,14 +1,14 @@ package services import ( - "go-api/handlers" + "arango-api/handlers" "os" + driver "github.com/arangodb/go-driver" "github.com/gin-gonic/gin" ) - -func DBMiddleware(db driver.Database,addr string) gin.HandlerFunc { +func DBMiddleware(db driver.Database, addr string) gin.HandlerFunc { return func(c *gin.Context) { c.Set("database", &db) @@ -17,17 +17,15 @@ func DBMiddleware(db driver.Database,addr string) gin.HandlerFunc { } } -func InitRouter(db driver.Database,addr string) *gin.Engine { +func InitRouter(db driver.Database, addr string) *gin.Engine { env := os.Getenv("ENV") - if env =="production"{ + if env == "production" { gin.SetMode(gin.ReleaseMode) } - - router := gin.Default() - + router := gin.Default() - router.Use(DBMiddleware(db,addr)) + router.Use(DBMiddleware(db, addr)) router.GET("/api/v1//Devices", handlers.GetDevices) router.POST("/api/v1//Devices", handlers.PostDevices) diff --git a/ARANGO_API/swagger.yaml b/ARANGO_API/swagger.yaml index d06573ea3..952a449bb 100644 --- a/ARANGO_API/swagger.yaml +++ b/ARANGO_API/swagger.yaml @@ -47,7 +47,7 @@ definitions: type: string x-go-name: Type type: object - x-go-package: go-api/models + x-go-package: arango-api/models DatabaseInfo: properties: database: @@ -79,7 +79,7 @@ definitions: type: string x-go-name: User type: object - x-go-package: go-api/models + x-go-package: arango-api/models Devices: properties: _key: @@ -153,7 +153,7 @@ definitions: type: string x-go-name: StorageGroupName type: object - x-go-package: go-api/models + x-go-package: arango-api/models ErrorResponse: properties: message: @@ -163,7 +163,7 @@ definitions: type: string x-go-name: Message type: object - x-go-package: go-api/models + x-go-package: arango-api/models SuccessConResponse: properties: Connections: @@ -174,7 +174,7 @@ definitions: $ref: '#/definitions/Connection' type: array type: object - x-go-package: go-api/models + x-go-package: arango-api/models SuccessResponse: properties: Devices: @@ -185,7 +185,7 @@ definitions: $ref: '#/definitions/Devices' type: array type: object - x-go-package: go-api/models + x-go-package: arango-api/models info: title: 'Arrango API:' version: 1.0.0 diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 22bf9e18d..67a21410f 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -86,10 +86,10 @@ services: container_name: ${COMPOSE_PROJECT_NAME}_arango_api environment: - ENV=production - - ARRANGO_URL=http://${COMPOSE_PROJECT_NAME}_arango_db:${ARANGO_PORT} - - ARRANGO_DATABASE=${ARANGO_DB} - - ARRANGO_USER=${ARANGO_USER} - - ARRANGO_PASSWORD=${ARANGO_PASS} + - ARANGO_URL=http://${COMPOSE_PROJECT_NAME}_arango_db:${ARANGO_PORT} + - ARANGO_DATABASE=${ARANGO_DB} + - ARANGO_USER=${ARANGO_USER} + - ARANGO_PASSWORD=${ARANGO_PASS} ports: - ${ARANGO_API_PORT}:8080 healthcheck: From 743ee446e290a07528eafd04b9aa1ae5bcd5f16f Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Fri, 4 Aug 2023 11:52:09 +0200 Subject: [PATCH 05/35] feat(Auth): add Authorization Bearer to arango api --- ARANGO_API/controllers/auth.go | 25 ++++++++++ ARANGO_API/dockerfile | 2 +- ARANGO_API/go.mod | 2 + ARANGO_API/go.sum | 4 ++ ARANGO_API/handlers/auth.go | 39 +++++++++++++++ ARANGO_API/handlers/connection.go | 70 ++++++++++++++------------- ARANGO_API/handlers/database.go | 25 +++++----- ARANGO_API/handlers/devices.go | 49 ++++++++++--------- ARANGO_API/main.go | 17 +++++-- ARANGO_API/models/auth.go | 29 +++++++++++ ARANGO_API/services/router.go | 34 +++++++++---- ARANGO_API/swagger.yaml | 62 ++++++++++++++++++++++++ ARANGO_API/utils/token/token.go | 80 +++++++++++++++++++++++++++++++ deploy/docker/.env | 3 ++ deploy/docker/docker-compose.yml | 3 ++ 15 files changed, 363 insertions(+), 81 deletions(-) create mode 100644 ARANGO_API/controllers/auth.go create mode 100644 ARANGO_API/handlers/auth.go create mode 100644 ARANGO_API/models/auth.go create mode 100644 ARANGO_API/utils/token/token.go diff --git a/ARANGO_API/controllers/auth.go b/ARANGO_API/controllers/auth.go new file mode 100644 index 000000000..f884e23b3 --- /dev/null +++ b/ARANGO_API/controllers/auth.go @@ -0,0 +1,25 @@ +package controllers + +import ( + "arango-api/models" + "arango-api/utils/token" + "fmt" + "os" +) +func CheckLogin(user models.LoginInput) (string,error){ + var u models.User + u.Username = user.Username + u.Password = user.Password + apiUser := os.Getenv("API_USER") + apiPassword := os.Getenv("API_PASSWORD") + if apiUser == u.Username && apiPassword == u.Password{ + token,err := token.GenerateToken(1235) + if err != nil { + fmt.Println(err) + return "",err + } + return token,nil + } + return "", fmt.Errorf("Bad username or password"); + +} \ No newline at end of file diff --git a/ARANGO_API/dockerfile b/ARANGO_API/dockerfile index 92e0247d5..b38fde977 100644 --- a/ARANGO_API/dockerfile +++ b/ARANGO_API/dockerfile @@ -9,7 +9,7 @@ COPY ARANGO_API/go.sum . RUN go mod download -COPY ARANGO_API/. . +COPY ARANGO_API . # Build the Go app diff --git a/ARANGO_API/go.mod b/ARANGO_API/go.mod index b0adac32b..3d6e01852 100644 --- a/ARANGO_API/go.mod +++ b/ARANGO_API/go.mod @@ -8,6 +8,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect @@ -26,6 +27,7 @@ require ( github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gorilla/mux v1.8.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect diff --git a/ARANGO_API/go.sum b/ARANGO_API/go.sum index eec00c320..aa2663bf4 100644 --- a/ARANGO_API/go.sum +++ b/ARANGO_API/go.sum @@ -17,6 +17,8 @@ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583j github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -101,6 +103,8 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= diff --git a/ARANGO_API/handlers/auth.go b/ARANGO_API/handlers/auth.go new file mode 100644 index 000000000..648f2f25b --- /dev/null +++ b/ARANGO_API/handlers/auth.go @@ -0,0 +1,39 @@ +package handlers + +import ( + "net/http" + "arango-api/models" + "arango-api/controllers" + "github.com/gin-gonic/gin" +) +// swagger:operation POST /Login Login LoginToApi +// Login to api +// --- +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessLogin" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func Login(c *gin.Context){ + var input models.LoginInput + + if err := c.BindJSON(&input); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + token, err := controllers.CheckLogin(input) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "username or password is incorrect."}) + return + } + + c.JSON(http.StatusOK, gin.H{"token":token}) + +} \ No newline at end of file diff --git a/ARANGO_API/handlers/connection.go b/ARANGO_API/handlers/connection.go index 6aa62bf02..1539b436d 100644 --- a/ARANGO_API/handlers/connection.go +++ b/ARANGO_API/handlers/connection.go @@ -28,19 +28,19 @@ import ( // description: To witch device // required: false // type: string -// +// security: +// - Bearer: [] // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessConResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessConResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func GetConnection(c *gin.Context) { conn, err := database.GetAll(c, "links") @@ -59,18 +59,19 @@ func GetConnection(c *gin.Context) { // Create new Connection // // --- +// security: +// - Bearer: [] // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessConResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessConResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func PostConnection(c *gin.Context) { var newConn map[string]string @@ -93,6 +94,8 @@ func PostConnection(c *gin.Context) { // Delete Connection by key // // --- +// security: +// - Bearer: [] // parameters: // - name: connection // in: path @@ -101,17 +104,16 @@ func PostConnection(c *gin.Context) { // type: string // // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func DeleteConnection(c *gin.Context) { key := c.Param("key") diff --git a/ARANGO_API/handlers/database.go b/ARANGO_API/handlers/database.go index 97fa0aa22..d279a01b2 100644 --- a/ARANGO_API/handlers/database.go +++ b/ARANGO_API/handlers/database.go @@ -13,6 +13,8 @@ import ( // Get database name // // --- +// security: +// - Bearer: [] // responses: // '200': // description: successful @@ -47,18 +49,19 @@ func GetBDD(c *gin.Context) { // Connect to new bdd // // --- +// security: +// - Bearer: [] // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func ConnectBDD(c *gin.Context) { db, err := database.GetDBConn(c) if err != nil && err.StatusCode != 404 { diff --git a/ARANGO_API/handlers/devices.go b/ARANGO_API/handlers/devices.go index 79f8158ee..da3ab82c4 100644 --- a/ARANGO_API/handlers/devices.go +++ b/ARANGO_API/handlers/devices.go @@ -33,6 +33,8 @@ import ( // description: Serial number of device // required: false // type: string +// security: +// - Bearer: [] // responses: // '200': // description: successful @@ -63,18 +65,19 @@ func GetDevices(c *gin.Context) { // Create new Devices // // --- +// security: +// - Bearer: [] // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func PostDevices(c *gin.Context) { var newDevices map[string]string @@ -116,19 +119,19 @@ func PostDevices(c *gin.Context) { // description: device looking for // required: true // type: string -// +// security: +// - Bearer: [] // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func DeleteDevice(c *gin.Context) { key := c.Param("key") diff --git a/ARANGO_API/main.go b/ARANGO_API/main.go index c9d6bf51b..bc75d418b 100644 --- a/ARANGO_API/main.go +++ b/ARANGO_API/main.go @@ -21,18 +21,29 @@ import ( "arango-api/services" "fmt" "os" + e "github.com/joho/godotenv" ) func main() { + + env := os.Getenv("ENV") + if env != "production" { + err := e.Load() + if err != nil { + fmt.Println("Some error occured. Err: ", err) + return + } + } + addr := os.Getenv("ARANGO_URL") bdd := os.Getenv("ARANGO_DATABASE") user := os.Getenv("ARANGO_USER") password := os.Getenv("ARANGO_PASSWORD") - db, err := database.ConnectToArrengo(addr,bdd, user, password) - if err != nil { - fmt.Println("Error connecting to database: ", err.Message) + db, err2 := database.ConnectToArrengo(addr,bdd, user, password) + if err2 != nil { + fmt.Println("Error connecting to database: ", err2.Message) return } diff --git a/ARANGO_API/models/auth.go b/ARANGO_API/models/auth.go new file mode 100644 index 000000000..b1395bb58 --- /dev/null +++ b/ARANGO_API/models/auth.go @@ -0,0 +1,29 @@ +package models + + +// swagger:model LoginInput +type LoginInput struct { + // username + // in: username + Username string `json:"username" binding:"required"` + // username + // in: password + Password string `json:"password" binding:"required"` +} + +type User struct { + ID uint `json:"id"` + Username string `json:"username" binding:"required"` + Password string `json:"password" binding:"required"` +} + +// swagger:model SuccessLogin +type SuccessLogin struct { + Token string `json:"token" binding:"required"` +} + +// swagger:parameters LoginToApi +type ReqLoginBody struct { + // in: body + Body LoginInput `json:"body"` +} diff --git a/ARANGO_API/services/router.go b/ARANGO_API/services/router.go index 8233ba7f9..212ec1034 100644 --- a/ARANGO_API/services/router.go +++ b/ARANGO_API/services/router.go @@ -3,7 +3,8 @@ package services import ( "arango-api/handlers" "os" - + "arango-api/utils/token" + "net/http" driver "github.com/arangodb/go-driver" "github.com/gin-gonic/gin" ) @@ -17,6 +18,18 @@ func DBMiddleware(db driver.Database, addr string) gin.HandlerFunc { } } +func JwtAuthMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + err := token.TokenValid(c) + if err != nil { + c.String(http.StatusUnauthorized, "Unauthorized") + c.Abort() + return + } + c.Next() + } +} + func InitRouter(db driver.Database, addr string) *gin.Engine { env := os.Getenv("ENV") if env == "production" { @@ -26,17 +39,20 @@ func InitRouter(db driver.Database, addr string) *gin.Engine { router := gin.Default() router.Use(DBMiddleware(db, addr)) + proteted := router.Group("/api/v1") + proteted.Use(JwtAuthMiddleware()) + proteted.GET("/Devices", handlers.GetDevices) + proteted.POST("/Devices", handlers.PostDevices) + proteted.DELETE("/Devices/:key", handlers.DeleteDevice) - router.GET("/api/v1//Devices", handlers.GetDevices) - router.POST("/api/v1//Devices", handlers.PostDevices) - router.DELETE("/api/v1//Devices/:key", handlers.DeleteDevice) + proteted.GET("/Connections", handlers.GetConnection) + proteted.POST("/Connections", handlers.PostConnection) + proteted.DELETE("/Connections/:key", handlers.DeleteConnection) - router.GET("/api/v1//Connections", handlers.GetConnection) - router.POST("/api/v1//Connections", handlers.PostConnection) - router.DELETE("/api/v1//Connections/:key", handlers.DeleteConnection) + proteted.GET("/Database", handlers.GetBDD) + proteted.POST("/Database", handlers.ConnectBDD) - router.GET("/api/v1/Database", handlers.GetBDD) - router.POST("/api/v1/Database", handlers.ConnectBDD) + router.POST("/api/v1/Login",handlers.Login) swagger := handlers.SwaggerHandler() router.Use(gin.WrapH(swagger)) diff --git a/ARANGO_API/swagger.yaml b/ARANGO_API/swagger.yaml index 952a449bb..ed713b69e 100644 --- a/ARANGO_API/swagger.yaml +++ b/ARANGO_API/swagger.yaml @@ -164,6 +164,22 @@ definitions: x-go-name: Message type: object x-go-package: arango-api/models + LoginInput: + properties: + password: + description: |- + username + in: password + type: string + x-go-name: Password + username: + description: |- + username + in: username + type: string + x-go-name: Username + type: object + x-go-package: arango-api/models SuccessConResponse: properties: Connections: @@ -175,6 +191,13 @@ definitions: type: array type: object x-go-package: arango-api/models + SuccessLogin: + properties: + token: + type: string + x-go-name: Token + type: object + x-go-package: arango-api/models SuccessResponse: properties: Devices: @@ -218,6 +241,8 @@ paths: schema: items: $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] tags: - Connections post: @@ -240,6 +265,8 @@ paths: schema: items: $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] tags: - Connections /Connections/{connection}: @@ -263,6 +290,8 @@ paths: schema: items: $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] tags: - Connections /Database: @@ -280,6 +309,8 @@ paths: schema: items: $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] tags: - Database post: @@ -302,6 +333,8 @@ paths: schema: items: $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] tags: - Database /Devices: @@ -336,6 +369,8 @@ paths: schema: items: $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] tags: - Devices post: @@ -358,6 +393,8 @@ paths: schema: items: $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] tags: - Devices /Devices/{device}: @@ -381,8 +418,33 @@ paths: schema: items: $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] tags: - Devices + /Login: + post: + description: Login to api + operationId: LoginToApi + parameters: + - in: body + name: body + schema: + $ref: '#/definitions/LoginInput' + x-go-name: Body + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/SuccessLogin' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + tags: + - Login produces: - application/json schemes: diff --git a/ARANGO_API/utils/token/token.go b/ARANGO_API/utils/token/token.go new file mode 100644 index 000000000..7ef3d4253 --- /dev/null +++ b/ARANGO_API/utils/token/token.go @@ -0,0 +1,80 @@ +package token + +import ( + "fmt" + "os" + "strconv" + "strings" + "time" + + "github.com/gin-gonic/gin" + jwt "github.com/dgrijalva/jwt-go" +) + +func GenerateToken(user_id uint) (string, error) { + /* + token_lifespan,err := strconv.Atoi(os.Getenv("TOKEN_HOUR_LIFESPAN")) + + if err != nil { + return "",err + } + */ + token_lifespan := 24 + claims := jwt.MapClaims{} + claims["authorized"] = true + claims["user_id"] = user_id + claims["exp"] = time.Now().Add(time.Hour * time.Duration(token_lifespan)).Unix() + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + return token.SignedString([]byte(os.Getenv("API_SECRET"))) + +} + +func TokenValid(c *gin.Context) error { + tokenString := ExtractToken(c) + _, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + } + return []byte(os.Getenv("API_SECRET")), nil + }) + if err != nil { + return err + } + return nil +} + +func ExtractToken(c *gin.Context) string { + token := c.Query("token") + if token != "" { + return token + } + bearerToken := c.Request.Header.Get("Authorization") + if len(strings.Split(bearerToken, " ")) == 2 { + return strings.Split(bearerToken, " ")[1] + } + return "" +} + +func ExtractTokenID(c *gin.Context) (uint, error) { + + tokenString := ExtractToken(c) + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + } + return []byte(os.Getenv("API_SECRET")), nil + }) + if err != nil { + return 0, err + } + claims, ok := token.Claims.(jwt.MapClaims) + if ok && token.Valid { + uid, err := strconv.ParseUint(fmt.Sprintf("%.0f", claims["user_id"]), 10, 32) + if err != nil { + return 0, err + } + return uint(uid), nil + } + return 0, nil +} \ No newline at end of file diff --git a/deploy/docker/.env b/deploy/docker/.env index 0c67d1b27..f3369fd74 100644 --- a/deploy/docker/.env +++ b/deploy/docker/.env @@ -17,4 +17,7 @@ ARANGO_PASS=ogree ARANGO_USER=root ARANGO_DB="_system" ARANGO_PORT=8529 +ARANGO_API_USER=root +ARANGO_API_PASSWORD=ogree +ARANGO_API_SECRET=myAwesomeApiSecret diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 67a21410f..cf002a503 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -90,6 +90,9 @@ services: - ARANGO_DATABASE=${ARANGO_DB} - ARANGO_USER=${ARANGO_USER} - ARANGO_PASSWORD=${ARANGO_PASS} + - API_USER=${ARANGO_API_USER} + - API_PASSWORD=${ARANGO_API_PASSWORD} + - API_SECRET=${ARANGO_API_SECRET} ports: - ${ARANGO_API_PORT}:8080 healthcheck: From 9cfa436897987411f0ec9aed32bde37e63f6eaea Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Fri, 4 Aug 2023 15:57:25 +0200 Subject: [PATCH 06/35] fix(health): add healthcheck on /api/v1/health --- ARANGO_API/services/router.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ARANGO_API/services/router.go b/ARANGO_API/services/router.go index 212ec1034..b081b6024 100644 --- a/ARANGO_API/services/router.go +++ b/ARANGO_API/services/router.go @@ -22,7 +22,7 @@ func JwtAuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { err := token.TokenValid(c) if err != nil { - c.String(http.StatusUnauthorized, "Unauthorized") + c.IndentedJSON(http.StatusUnauthorized,gin.H{"message":"Unauthorized"}) c.Abort() return } @@ -53,6 +53,9 @@ func InitRouter(db driver.Database, addr string) *gin.Engine { proteted.POST("/Database", handlers.ConnectBDD) router.POST("/api/v1/Login",handlers.Login) + router.GET("/api/v1/health",func(c *gin.Context){ + c.String(http.StatusAccepted,"") + }) swagger := handlers.SwaggerHandler() router.Use(gin.WrapH(swagger)) From fb7c017d231d61823f8b4bf8b046b86c4ff8b6df Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Fri, 4 Aug 2023 17:43:07 +0200 Subject: [PATCH 07/35] feat(device): get device connected to another --- ARANGO_API/database/common.go | 2 +- ARANGO_API/database/connection.go | 2 ++ ARANGO_API/database/devices.go | 26 ++++++++++++++ ARANGO_API/handlers/connection.go | 2 ++ ARANGO_API/handlers/devices.go | 59 +++++++++++++++++++++++++++++++ ARANGO_API/services/router.go | 1 + ARANGO_API/swagger.yaml | 41 +++++++++++++++++++++ 7 files changed, 132 insertions(+), 1 deletion(-) diff --git a/ARANGO_API/database/common.go b/ARANGO_API/database/common.go index ac8be87b1..d5800fd9d 100644 --- a/ARANGO_API/database/common.go +++ b/ARANGO_API/database/common.go @@ -68,7 +68,7 @@ func GetAll(c *gin.Context, col string) ([]interface{}, *models.ErrorMessage) { querystring := "FOR doc IN " + col for key, value := range values { - querystring += " FILTER doc." + key + " == \"" + value[0] + "\" " + querystring += " FILTER doc." + key + " LIKE \"" + value[0] + "\" " } querystring += " RETURN doc" result, err := ExecQuerry(*db, querystring) diff --git a/ARANGO_API/database/connection.go b/ARANGO_API/database/connection.go index fa19a9a7c..9a658cf04 100644 --- a/ARANGO_API/database/connection.go +++ b/ARANGO_API/database/connection.go @@ -42,3 +42,5 @@ func InsertConnection(c *gin.Context, conn map[string]string) ([]interface{}, *m } return result, nil } + + diff --git a/ARANGO_API/database/devices.go b/ARANGO_API/database/devices.go index 8430968a5..f2053c7aa 100644 --- a/ARANGO_API/database/devices.go +++ b/ARANGO_API/database/devices.go @@ -6,6 +6,7 @@ import ( driver "github.com/arangodb/go-driver" "github.com/gin-gonic/gin" + ) func DeviceExistedById(db driver.Database, id string) (bool, *models.ErrorMessage) { @@ -68,3 +69,28 @@ func InsertDevices(c *gin.Context, device map[string]string) ([]interface{}, *mo } return result, nil } + + +func GetDevicesConnectedTo(c *gin.Context, keyDevice string)([]interface{}, *models.ErrorMessage){ + db, err := GetDBConn(c) + if err != nil { + return nil, err + } + values := c.Request.URL.Query() + + querystring := "FOR doc IN links" + querystring += " FILTER doc._from == \"devices/"+keyDevice+"\"" + querystring += " FOR device IN devices" + querystring += " FILTER device._id == doc._to" + + for key, value := range values { + querystring += " FILTER device." + key + " LIKE \"" + value[0] + "\" " + } + querystring += " RETURN device" + + result, err := ExecQuerry(*db, querystring) + if err != nil { + return nil, err + } + return result, nil +} diff --git a/ARANGO_API/handlers/connection.go b/ARANGO_API/handlers/connection.go index 1539b436d..d6195d059 100644 --- a/ARANGO_API/handlers/connection.go +++ b/ARANGO_API/handlers/connection.go @@ -124,3 +124,5 @@ func DeleteConnection(c *gin.Context) { } c.IndentedJSON(http.StatusOK, conn) } + + diff --git a/ARANGO_API/handlers/devices.go b/ARANGO_API/handlers/devices.go index da3ab82c4..98760d633 100644 --- a/ARANGO_API/handlers/devices.go +++ b/ARANGO_API/handlers/devices.go @@ -61,6 +61,65 @@ func GetDevices(c *gin.Context) { c.IndentedJSON(http.StatusOK, devices) } +// swagger:operation GET /Devices/{device}/Connected Devices GetDevicesConnectedTo +// Get Devices connected to a device +// +// --- +// parameters: +// - name: device +// in: path +// description: Key of device +// required: true +// type: string +// - name: _key +// in: query +// description: Filter devices by key +// required: false +// type: string +// - name: _name +// in: query +// description: Name of device +// required: false +// type: string +// - name: group_name +// in: query +// description: Group_name of device +// required: false +// type: string +// - name: serial +// in: query +// description: Serial number of device +// required: false +// type: string +// security: +// - Bearer: [] +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" + +func GetDevicesConnectedTo(c *gin.Context) { + + key := c.Param("key") + devices, err := database.GetDevicesConnectedTo(c, key) + if err != nil { + c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) + return + } + if len(devices) == 0 { + c.IndentedJSON(http.StatusNotFound, gin.H{"message": "Devices not found"}) + return + } + c.IndentedJSON(http.StatusOK, devices) +} + // swagger:operation POST /Devices Devices CreateDevices // Create new Devices // diff --git a/ARANGO_API/services/router.go b/ARANGO_API/services/router.go index b081b6024..c37c307c8 100644 --- a/ARANGO_API/services/router.go +++ b/ARANGO_API/services/router.go @@ -44,6 +44,7 @@ func InitRouter(db driver.Database, addr string) *gin.Engine { proteted.GET("/Devices", handlers.GetDevices) proteted.POST("/Devices", handlers.PostDevices) proteted.DELETE("/Devices/:key", handlers.DeleteDevice) + proteted.GET("/Devices/:key/Connected", handlers.GetDevicesConnectedTo) proteted.GET("/Connections", handlers.GetConnection) proteted.POST("/Connections", handlers.PostConnection) diff --git a/ARANGO_API/swagger.yaml b/ARANGO_API/swagger.yaml index ed713b69e..06d7fd46c 100644 --- a/ARANGO_API/swagger.yaml +++ b/ARANGO_API/swagger.yaml @@ -422,6 +422,47 @@ paths: - Bearer: [] tags: - Devices + /Devices/{device}/Connected: + get: + description: Get Devices connected to a device + operationId: GetDevicesConnectedTo + parameters: + - description: Key of device + in: path + name: device + required: true + type: string + - description: Filter devices by key + in: query + name: _key + type: string + - description: Name of device + in: query + name: _name + type: string + - description: Group_name of device + in: query + name: group_name + type: string + - description: Serial number of device + in: query + name: serial + type: string + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/SuccessResponse' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] + tags: + - Devices /Login: post: description: Login to api From 4426b95bd1954dd8bd6f57e4ebed3264c1282741 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Mon, 7 Aug 2023 09:04:28 +0200 Subject: [PATCH 08/35] fix(router): rename route getDevicesConnecteTo --- ARANGO_API/database/common.go | 4 +--- ARANGO_API/handlers/database.go | 2 +- ARANGO_API/handlers/devices.go | 2 +- ARANGO_API/main.go | 3 ++- ARANGO_API/services/router.go | 2 +- ARANGO_API/swagger.yaml | 2 +- deploy/docker/.env | 4 ++-- swagger.yaml | 2 ++ 8 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 swagger.yaml diff --git a/ARANGO_API/database/common.go b/ARANGO_API/database/common.go index d5800fd9d..75589961c 100644 --- a/ARANGO_API/database/common.go +++ b/ARANGO_API/database/common.go @@ -114,7 +114,7 @@ func Update(c *gin.Context, doc interface{}, key, col string) ([]interface{}, *m return result, nil } -func ConnectToArrengo(addr, database, user, password string) (driver.Database, *models.ErrorMessage) { +func ConnectToArango(addr, database, user, password string) (driver.Database, *models.ErrorMessage) { conn, err := http.NewConnection(http.ConnectionConfig{ Endpoints: []string{addr}, @@ -122,7 +122,6 @@ func ConnectToArrengo(addr, database, user, password string) (driver.Database, * if err != nil { return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest, Message: err.Error()} } - client, err := driver.NewClient(driver.ClientConfig{ Connection: conn, Authentication: driver.BasicAuthentication(user, password), @@ -130,7 +129,6 @@ func ConnectToArrengo(addr, database, user, password string) (driver.Database, * if err != nil { return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest, Message: err.Error()} } - db, err := client.Database(nil, database) if err != nil { return nil, &models.ErrorMessage{StatusCode: h.StatusBadRequest, Message: err.Error()} diff --git a/ARANGO_API/handlers/database.go b/ARANGO_API/handlers/database.go index d279a01b2..0c0395546 100644 --- a/ARANGO_API/handlers/database.go +++ b/ARANGO_API/handlers/database.go @@ -81,7 +81,7 @@ func ConnectBDD(c *gin.Context) { return } - newDB, err := database.ConnectToArrengo(DBInfo.Host, DBInfo.Database, DBInfo.User, DBInfo.Password) + newDB, err := database.ConnectToArango(DBInfo.Host, DBInfo.Database, DBInfo.User, DBInfo.Password) if err != nil { c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) diff --git a/ARANGO_API/handlers/devices.go b/ARANGO_API/handlers/devices.go index 98760d633..fc6e95d8a 100644 --- a/ARANGO_API/handlers/devices.go +++ b/ARANGO_API/handlers/devices.go @@ -61,7 +61,7 @@ func GetDevices(c *gin.Context) { c.IndentedJSON(http.StatusOK, devices) } -// swagger:operation GET /Devices/{device}/Connected Devices GetDevicesConnectedTo +// swagger:operation GET /Devices/ConnecteTo/{device} Devices GetDevicesConnectedTo // Get Devices connected to a device // // --- diff --git a/ARANGO_API/main.go b/ARANGO_API/main.go index bc75d418b..7d82ab0cf 100644 --- a/ARANGO_API/main.go +++ b/ARANGO_API/main.go @@ -28,6 +28,7 @@ func main() { env := os.Getenv("ENV") if env != "production" { + fmt.Println("Loading environment variables from .env") err := e.Load() if err != nil { fmt.Println("Some error occured. Err: ", err) @@ -41,7 +42,7 @@ func main() { password := os.Getenv("ARANGO_PASSWORD") - db, err2 := database.ConnectToArrengo(addr,bdd, user, password) + db, err2 := database.ConnectToArango(addr,bdd, user, password) if err2 != nil { fmt.Println("Error connecting to database: ", err2.Message) return diff --git a/ARANGO_API/services/router.go b/ARANGO_API/services/router.go index c37c307c8..73858432a 100644 --- a/ARANGO_API/services/router.go +++ b/ARANGO_API/services/router.go @@ -44,7 +44,7 @@ func InitRouter(db driver.Database, addr string) *gin.Engine { proteted.GET("/Devices", handlers.GetDevices) proteted.POST("/Devices", handlers.PostDevices) proteted.DELETE("/Devices/:key", handlers.DeleteDevice) - proteted.GET("/Devices/:key/Connected", handlers.GetDevicesConnectedTo) + proteted.GET("/Devices/ConnecteTo/:key", handlers.GetDevicesConnectedTo) proteted.GET("/Connections", handlers.GetConnection) proteted.POST("/Connections", handlers.PostConnection) diff --git a/ARANGO_API/swagger.yaml b/ARANGO_API/swagger.yaml index 06d7fd46c..19a99981f 100644 --- a/ARANGO_API/swagger.yaml +++ b/ARANGO_API/swagger.yaml @@ -422,7 +422,7 @@ paths: - Bearer: [] tags: - Devices - /Devices/{device}/Connected: + /Devices/ConnecteTo/{device}: get: description: Get Devices connected to a device operationId: GetDevicesConnectedTo diff --git a/deploy/docker/.env b/deploy/docker/.env index f3369fd74..bf80b7827 100644 --- a/deploy/docker/.env +++ b/deploy/docker/.env @@ -13,9 +13,9 @@ IMAGE_TAG=main #ARANGODB_ ARANGO_API_BUILD_DIR=ARANGO_API ARANGO_API_PORT=8080 -ARANGO_PASS=ogree +ARANGO_PASS=password ARANGO_USER=root -ARANGO_DB="_system" +ARANGO_DB=_system ARANGO_PORT=8529 ARANGO_API_USER=root ARANGO_API_PASSWORD=ogree diff --git a/swagger.yaml b/swagger.yaml new file mode 100644 index 000000000..a26c975cb --- /dev/null +++ b/swagger.yaml @@ -0,0 +1,2 @@ +paths: {} +swagger: "2.0" From 1039333bbe4977799ccc9bc1f452b8d33ed0c0c5 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Mon, 7 Aug 2023 09:41:07 +0200 Subject: [PATCH 09/35] feat(bff): init bff --- .gitignore | 5 +++ BFF/controllers/auth.go | 25 ++++++++++++ BFF/go.mod | 3 ++ BFF/handlers/auth.go | 39 ++++++++++++++++++ BFF/handlers/swagger.go | 19 +++++++++ BFF/main.go | 48 +++++++++++++++++++++++ BFF/models/api.go | 8 ++++ BFF/models/auth.go | 29 ++++++++++++++ BFF/models/http.go | 22 +++++++++++ BFF/services/router.go | 46 ++++++++++++++++++++++ BFF/swagger.yaml | 85 ++++++++++++++++++++++++++++++++++++++++ BFF/utils/token/token.go | 80 +++++++++++++++++++++++++++++++++++++ 12 files changed, 409 insertions(+) create mode 100644 BFF/controllers/auth.go create mode 100644 BFF/go.mod create mode 100644 BFF/handlers/auth.go create mode 100644 BFF/handlers/swagger.go create mode 100644 BFF/main.go create mode 100644 BFF/models/api.go create mode 100644 BFF/models/auth.go create mode 100644 BFF/models/http.go create mode 100644 BFF/services/router.go create mode 100644 BFF/swagger.yaml create mode 100644 BFF/utils/token/token.go diff --git a/.gitignore b/.gitignore index df86fe1e2..2dd59cc36 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,8 @@ deploy/docker/app-deploy #ARANGO_API Ignore ARANGO_API/arango-api ARANGO_API/*env + +#BFF Ignore +BFF/*env +BFF/ogree-bff + diff --git a/BFF/controllers/auth.go b/BFF/controllers/auth.go new file mode 100644 index 000000000..c248d4a25 --- /dev/null +++ b/BFF/controllers/auth.go @@ -0,0 +1,25 @@ +package controllers + +import ( + "ogree-bff/models" + "ogree-bff/utils/token" + "fmt" + "os" +) +func CheckLogin(user models.LoginInput) (string,error){ + var u models.User + u.Username = user.Username + u.Password = user.Password + apiUser := os.Getenv("BFF_USER") + apiPassword := os.Getenv("BFF_PASSWORD") + if apiUser == u.Username && apiPassword == u.Password{ + token,err := token.GenerateToken(1235) + if err != nil { + fmt.Println(err) + return "",err + } + return token,nil + } + return "", fmt.Errorf("Bad username or password"); + +} \ No newline at end of file diff --git a/BFF/go.mod b/BFF/go.mod new file mode 100644 index 000000000..72e8ec78f --- /dev/null +++ b/BFF/go.mod @@ -0,0 +1,3 @@ +module ogree-bff + +go 1.20 diff --git a/BFF/handlers/auth.go b/BFF/handlers/auth.go new file mode 100644 index 000000000..20d0607c8 --- /dev/null +++ b/BFF/handlers/auth.go @@ -0,0 +1,39 @@ +package handlers + +import ( + "net/http" + "ogree-bff/models" + "ogree-bff/controllers" + "github.com/gin-gonic/gin" +) +// swagger:operation POST /Login Login LoginToApi +// Login to api +// --- +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessLogin" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func Login(c *gin.Context){ + var input models.LoginInput + + if err := c.BindJSON(&input); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + token, err := controllers.CheckLogin(input) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "username or password is incorrect."}) + return + } + + c.JSON(http.StatusOK, gin.H{"token":token}) + +} \ No newline at end of file diff --git a/BFF/handlers/swagger.go b/BFF/handlers/swagger.go new file mode 100644 index 000000000..9ef47db78 --- /dev/null +++ b/BFF/handlers/swagger.go @@ -0,0 +1,19 @@ +package handlers + +import( + "net/http" + "github.com/go-openapi/runtime/middleware" + "github.com/gorilla/mux" +) + +func SwaggerHandler() *mux.Router{ + pr := mux.NewRouter() + + pr.Handle("/swagger.yaml", http.FileServer(http.Dir("./"))) + opts := middleware.SwaggerUIOpts{SpecURL: "swagger.yaml"} + sh := middleware.SwaggerUI(opts, nil) + pr.Handle("/docs", sh) + + return pr + +} \ No newline at end of file diff --git a/BFF/main.go b/BFF/main.go new file mode 100644 index 000000000..a946fb967 --- /dev/null +++ b/BFF/main.go @@ -0,0 +1,48 @@ +// Ogree BFF: +// version: 1.0.0 +// title: Awsome API +// Schemes: http, https +// Host: +// BasePath: /api/v1 +// Consumes: +// - application/json +// Produces: +// - application/json +// SecurityDefinitions: +// Bearer: +// type: apiKey +// name: Authorization +// in: header +// swagger:meta +package main + +import ( + + "fmt" + "os" + e "github.com/joho/godotenv" + "ogree-bff/models" + "ogree-bff/services" +) + +func main() { + + env := os.Getenv("ENV") + if env != "production" { + fmt.Println("Loading environment variables from .env") + err := e.Load() + if err != nil { + fmt.Println("Some error occured. Err: ", err) + return + } + } + + ArangoUrl := os.Getenv("ARANGO_URL") + apiList := []models.API { + {Name: "Arango", URL: ArangoUrl}, + } + + + router := services.InitRouter(apiList,env) + router.Run(":8080") +} diff --git a/BFF/models/api.go b/BFF/models/api.go new file mode 100644 index 000000000..368ae490b --- /dev/null +++ b/BFF/models/api.go @@ -0,0 +1,8 @@ +package models + +type API struct { + + Name string `json:"name"` + URL string `json:"url"` + +} \ No newline at end of file diff --git a/BFF/models/auth.go b/BFF/models/auth.go new file mode 100644 index 000000000..b1395bb58 --- /dev/null +++ b/BFF/models/auth.go @@ -0,0 +1,29 @@ +package models + + +// swagger:model LoginInput +type LoginInput struct { + // username + // in: username + Username string `json:"username" binding:"required"` + // username + // in: password + Password string `json:"password" binding:"required"` +} + +type User struct { + ID uint `json:"id"` + Username string `json:"username" binding:"required"` + Password string `json:"password" binding:"required"` +} + +// swagger:model SuccessLogin +type SuccessLogin struct { + Token string `json:"token" binding:"required"` +} + +// swagger:parameters LoginToApi +type ReqLoginBody struct { + // in: body + Body LoginInput `json:"body"` +} diff --git a/BFF/models/http.go b/BFF/models/http.go new file mode 100644 index 000000000..97e91c1d7 --- /dev/null +++ b/BFF/models/http.go @@ -0,0 +1,22 @@ +package models + +// swagger:model ErrorResponse +type ErrorResponse struct { + // Error Response Message + // in: message + Message string `json:"message"` +} + +// swagger:model SuccessResponse +type SuccessResponse struct { + // Error Response Message + // in: message + Message string `json:"message"` +} + + +type Message struct { + + StatusCode int `json:"statuscode"` + Message string `json:"message"` +} diff --git a/BFF/services/router.go b/BFF/services/router.go new file mode 100644 index 000000000..e035bfeeb --- /dev/null +++ b/BFF/services/router.go @@ -0,0 +1,46 @@ +package services + +import ( + "ogree-bff/handlers" + "ogree-bff/utils/token" + "net/http" + "ogree-bff/models" + +// driver "github.com/arangodb/go-driver" + "github.com/gin-gonic/gin" +) + + + +func JwtAuthMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + err := token.TokenValid(c) + if err != nil { + c.IndentedJSON(http.StatusUnauthorized,gin.H{"message":"Unauthorized"}) + c.Abort() + return + } + c.Next() + } +} + +func InitRouter(apiList []models.API,env string ) *gin.Engine { + if env == "production" { + gin.SetMode(gin.ReleaseMode) + } + + router := gin.Default() + + proteted := router.Group("/api/v1") + proteted.Use(JwtAuthMiddleware()) + + router.POST("/api/v1/Login",handlers.Login) + router.GET("/api/v1/health",func(c *gin.Context){ + c.String(http.StatusAccepted,"") + }) + + swagger := handlers.SwaggerHandler() + router.Use(gin.WrapH(swagger)) + + return router +} diff --git a/BFF/swagger.yaml b/BFF/swagger.yaml new file mode 100644 index 000000000..d6e06680e --- /dev/null +++ b/BFF/swagger.yaml @@ -0,0 +1,85 @@ +basePath: /api/v1 +consumes: + - application/json +definitions: + ErrorResponse: + properties: + message: + description: |- + Error Response Message + in: message + type: string + x-go-name: Message + type: object + x-go-package: ogree-bff/models + LoginInput: + properties: + password: + description: |- + username + in: password + type: string + x-go-name: Password + username: + description: |- + username + in: username + type: string + x-go-name: Username + type: object + x-go-package: ogree-bff/models + SuccessLogin: + properties: + token: + type: string + x-go-name: Token + type: object + x-go-package: ogree-bff/models + SuccessResponse: + properties: + message: + description: |- + Error Response Message + in: message + type: string + x-go-name: Message + type: object + x-go-package: ogree-bff/models +info: + title: 'Ogree BFF:' + version: 1.0.0 +paths: + /Login: + post: + description: Login to api + operationId: LoginToApi + parameters: + - in: body + name: body + schema: + $ref: '#/definitions/LoginInput' + x-go-name: Body + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/SuccessLogin' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + tags: + - Login +produces: + - application/json +schemes: + - http + - https +securityDefinitions: + Bearer: + in: header + name: Authorization + type: apiKey +swagger: "2.0" diff --git a/BFF/utils/token/token.go b/BFF/utils/token/token.go new file mode 100644 index 000000000..e3805b145 --- /dev/null +++ b/BFF/utils/token/token.go @@ -0,0 +1,80 @@ +package token + +import ( + "fmt" + "os" + "strconv" + "strings" + "time" + + "github.com/gin-gonic/gin" + jwt "github.com/dgrijalva/jwt-go" +) + +func GenerateToken(user_id uint) (string, error) { + /* + token_lifespan,err := strconv.Atoi(os.Getenv("TOKEN_HOUR_LIFESPAN")) + + if err != nil { + return "",err + } + */ + token_lifespan := 24 + claims := jwt.MapClaims{} + claims["authorized"] = true + claims["user_id"] = user_id + claims["exp"] = time.Now().Add(time.Hour * time.Duration(token_lifespan)).Unix() + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + return token.SignedString([]byte(os.Getenv("BFF_SECRET"))) + +} + +func TokenValid(c *gin.Context) error { + tokenString := ExtractToken(c) + _, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + } + return []byte(os.Getenv("BFF_SECRET")), nil + }) + if err != nil { + return err + } + return nil +} + +func ExtractToken(c *gin.Context) string { + token := c.Query("token") + if token != "" { + return token + } + bearerToken := c.Request.Header.Get("Authorization") + if len(strings.Split(bearerToken, " ")) == 2 { + return strings.Split(bearerToken, " ")[1] + } + return "" +} + +func ExtractTokenID(c *gin.Context) (uint, error) { + + tokenString := ExtractToken(c) + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + } + return []byte(os.Getenv("BFF_SECRET")), nil + }) + if err != nil { + return 0, err + } + claims, ok := token.Claims.(jwt.MapClaims) + if ok && token.Valid { + uid, err := strconv.ParseUint(fmt.Sprintf("%.0f", claims["user_id"]), 10, 32) + if err != nil { + return 0, err + } + return uint(uid), nil + } + return 0, nil +} \ No newline at end of file From 8ef5fdc103aa707ff7c85339929e403d83b044f8 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Tue, 8 Aug 2023 09:52:37 +0200 Subject: [PATCH 10/35] feat(bff): add route Organization and Objects --- ARANGO_API/handlers/auth.go | 2 +- ARANGO_API/main.go | 2 +- ARANGO_API/services/router.go | 8 +- ARANGO_API/swagger.yaml | 4 +- BFF/controllers/auth.go | 25 - BFF/controllers/sender.go | 166 ++++++ BFF/handlers/auth.go | 143 +++++- BFF/handlers/devices.go | 97 ++++ BFF/handlers/object.go | 586 +++++++++++++++++++++ BFF/handlers/organization.go | 183 +++++++ BFF/main.go | 15 +- BFF/models/auth.go | 8 +- BFF/models/http.go | 2 +- BFF/services/router.go | 97 +++- BFF/swagger.yaml | 841 ++++++++++++++++++++++++++++++- deploy/docker/docker-compose.yml | 5 +- 16 files changed, 2089 insertions(+), 95 deletions(-) delete mode 100644 BFF/controllers/auth.go create mode 100644 BFF/controllers/sender.go create mode 100644 BFF/handlers/devices.go create mode 100644 BFF/handlers/object.go create mode 100644 BFF/handlers/organization.go diff --git a/ARANGO_API/handlers/auth.go b/ARANGO_API/handlers/auth.go index 648f2f25b..6fbe1db37 100644 --- a/ARANGO_API/handlers/auth.go +++ b/ARANGO_API/handlers/auth.go @@ -6,7 +6,7 @@ import ( "arango-api/controllers" "github.com/gin-gonic/gin" ) -// swagger:operation POST /Login Login LoginToApi +// swagger:operation POST /login Login LoginToApi // Login to api // --- // responses: diff --git a/ARANGO_API/main.go b/ARANGO_API/main.go index 7d82ab0cf..39c8ae34b 100644 --- a/ARANGO_API/main.go +++ b/ARANGO_API/main.go @@ -3,7 +3,7 @@ // title: Awsome API // Schemes: http, https // Host: -// BasePath: /api/v1 +// BasePath: /api // Consumes: // - application/json // Produces: diff --git a/ARANGO_API/services/router.go b/ARANGO_API/services/router.go index 73858432a..d80641978 100644 --- a/ARANGO_API/services/router.go +++ b/ARANGO_API/services/router.go @@ -39,8 +39,8 @@ func InitRouter(db driver.Database, addr string) *gin.Engine { router := gin.Default() router.Use(DBMiddleware(db, addr)) - proteted := router.Group("/api/v1") - proteted.Use(JwtAuthMiddleware()) + proteted := router.Group("/api") + //proteted.Use(JwtAuthMiddleware()) proteted.GET("/Devices", handlers.GetDevices) proteted.POST("/Devices", handlers.PostDevices) proteted.DELETE("/Devices/:key", handlers.DeleteDevice) @@ -53,8 +53,8 @@ func InitRouter(db driver.Database, addr string) *gin.Engine { proteted.GET("/Database", handlers.GetBDD) proteted.POST("/Database", handlers.ConnectBDD) - router.POST("/api/v1/Login",handlers.Login) - router.GET("/api/v1/health",func(c *gin.Context){ + router.POST("/api/login",handlers.Login) + router.GET("/api/health",func(c *gin.Context){ c.String(http.StatusAccepted,"") }) diff --git a/ARANGO_API/swagger.yaml b/ARANGO_API/swagger.yaml index 19a99981f..d0ad9b95a 100644 --- a/ARANGO_API/swagger.yaml +++ b/ARANGO_API/swagger.yaml @@ -1,4 +1,4 @@ -basePath: /api/v1 +basePath: /api consumes: - application/json definitions: @@ -463,7 +463,7 @@ paths: - Bearer: [] tags: - Devices - /Login: + /login: post: description: Login to api operationId: LoginToApi diff --git a/BFF/controllers/auth.go b/BFF/controllers/auth.go deleted file mode 100644 index c248d4a25..000000000 --- a/BFF/controllers/auth.go +++ /dev/null @@ -1,25 +0,0 @@ -package controllers - -import ( - "ogree-bff/models" - "ogree-bff/utils/token" - "fmt" - "os" -) -func CheckLogin(user models.LoginInput) (string,error){ - var u models.User - u.Username = user.Username - u.Password = user.Password - apiUser := os.Getenv("BFF_USER") - apiPassword := os.Getenv("BFF_PASSWORD") - if apiUser == u.Username && apiPassword == u.Password{ - token,err := token.GenerateToken(1235) - if err != nil { - fmt.Println(err) - return "",err - } - return token,nil - } - return "", fmt.Errorf("Bad username or password"); - -} \ No newline at end of file diff --git a/BFF/controllers/sender.go b/BFF/controllers/sender.go new file mode 100644 index 000000000..e7ecf8df1 --- /dev/null +++ b/BFF/controllers/sender.go @@ -0,0 +1,166 @@ +package controllers + +import ( + "bytes" + "encoding/json" + "fmt" + + "io" + "net/http" + "ogree-bff/models" + "ogree-bff/utils/token" + + "github.com/gin-gonic/gin" +) + +func GetQueryString(c *gin.Context) (string) { + query := "" + for key,value := range c.Request.URL.Query() { + if query == ""{ + query+="?"+key+"="+value[0] + }else{ + query+="&"+key+"="+value[0] + } + } + return query +} + +func GetPath(c *gin.Context) (string) { + return c.Request.URL.Path +} + +func Send(method, URL, query ,key string, data interface{}) (*http.Response,error) { + client := &http.Client{} + dataJSON, err := json.Marshal(data) + if err != nil { + return nil,err + } + req, err := http.NewRequest(method, URL+query, bytes.NewBuffer(dataJSON)) + if err != nil { + return nil,err + } + req.Header.Set("Authorization", "Bearer "+key) + resp,err := client.Do(req) + if err != nil { + return nil,err + } + + return resp, nil +} + +func GetJSONBody(resp *http.Response) models.Message { + defer resp.Body.Close() + var responseBody interface{} + body, err := io.ReadAll(resp.Body) + + if err != nil { + return models.Message{StatusCode: http.StatusInternalServerError,Message: err.Error()} + } + fmt.Println(string(body)) + err = json.Unmarshal(body, &responseBody) + if err != nil { + return models.Message{StatusCode: http.StatusInternalServerError,Message: err.Error()} + } + return models.Message{StatusCode: http.StatusAccepted,Message: responseBody} +} + +func Get(c *gin.Context, api string){ + url, ok := c.Value(api).(string) + if !ok { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Failed to get api connection"}) + return + } + key := token.ExtractToken(c) + query := GetQueryString(c) + path := GetPath(c) + resp,err := Send("GET",url+path,query,key,nil) + if err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + result := GetJSONBody(resp) + c.IndentedJSON(resp.StatusCode, result.Message) + return +} + +func Post(c *gin.Context, api string){ + url, ok := c.Value(api).(string) + if !ok { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Failed to get api connection"}) + return + } + var data interface{} + // Call BindJSON to bind the received JSON to + if err := c.ShouldBindJSON(&data); err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + key := token.ExtractToken(c) + path := GetPath(c) + resp,err := Send("POST",url+path,"",key,data) + if err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + } + result := GetJSONBody(resp) + c.IndentedJSON(resp.StatusCode, result.Message) +} + +func Delete(c *gin.Context, api string){ + url, ok := c.Value(api).(string) + if !ok { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Failed to get api connection"}) + return + } + key := token.ExtractToken(c) + path := GetPath(c) + resp,err := Send("DELETE",url+path,"",key,nil) + if err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + } + result := GetJSONBody(resp) + c.IndentedJSON(resp.StatusCode, result.Message) +} + +func Patch(c *gin.Context, api string){ + url, ok := c.Value(api).(string) + if !ok { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Failed to get api connection"}) + return + } + var data interface{} + // Call BindJSON to bind the received JSON to + if err := c.ShouldBindJSON(&data); err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + key := token.ExtractToken(c) + path := GetPath(c) + resp,err := Send("PATCH",url+path,"",key,data) + if err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + } + result := GetJSONBody(resp) + c.IndentedJSON(resp.StatusCode, result.Message) +} + +func Put(c *gin.Context, api string){ + url, ok := c.Value(api).(string) + if !ok { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Failed to get api connection"}) + return + } + var data interface{} + // Call BindJSON to bind the received JSON to + if err := c.ShouldBindJSON(&data); err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + key := token.ExtractToken(c) + path := GetPath(c) + resp,err := Send("PUT",url+path,"",key,data) + if err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + } + result := GetJSONBody(resp) + c.IndentedJSON(resp.StatusCode, result.Message) +} \ No newline at end of file diff --git a/BFF/handlers/auth.go b/BFF/handlers/auth.go index 20d0607c8..fc7ae86bc 100644 --- a/BFF/handlers/auth.go +++ b/BFF/handlers/auth.go @@ -1,39 +1,130 @@ package handlers import ( - "net/http" - "ogree-bff/models" "ogree-bff/controllers" - "github.com/gin-gonic/gin" + + "github.com/gin-gonic/gin" ) -// swagger:operation POST /Login Login LoginToApi -// Login to api + +// swagger:operation POST /login Authentication Authenticate +// Generates a new JWT Key for the client. +// Create a new JWT Key. This can also be used to verify credentials +// The authorize and 'Try it out' buttons don't work // --- +// produces: +// - application/json +// parameters: +// - name: body +// in: body +// description: 'Mandatory: email and password.' +// required: true +// format: object +// example: '{"email": "user@test.com", "password": "secret123"}' // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessLogin" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: Authenticated +// '400': +// description: Bad request +// '500': +// description: Internal server error func Login(c *gin.Context){ - var input models.LoginInput + controllers.Post(c,"mongo") +} - if err := c.BindJSON(&input); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } +// swagger:operation GET /token/valid Authentication VerifyToken +// Verify if token sent in the header is valid. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// responses: +// '200': +// description: Token is valid. +// '403': +// description: Unauthorized +// '500': +// description: Internal server error +func ValidToken(c *gin.Context){ + controllers.Get(c,"mongo") - token, err := controllers.CheckLogin(input) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "username or password is incorrect."}) - return - } +} - c.JSON(http.StatusOK, gin.H{"token":token}) +// swagger:operation POST /users/password/change Authentication ModifyUserPassword +// For logged in user to change its own password. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: body +// in: body +// description: 'Mandatory: currentPassword and newPassword.' +// type: json +// required: true +// example: '{"currentPassword": "myOldPassword", "newPassword": "myNewPassword"}' +// +// responses: +// '200': +// description: Password changed +// '400': +// description: Bad request +// '500': +// description: Internal server error +func ModifyUserPassword(c *gin.Context){ + controllers.Post(c,"mongo") +} +// swagger:operation POST /users/password/reset Authentication ResetUserPassword +// Reset password after forgot. +// For user that first called forgot enpoint to change its password. +// A reset token generated by the forgot endpoint should be provided as the Authentication header. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: body +// in: body +// description: 'Mandatory: currentPassword and newPassword.' +// type: json +// required: true +// example: '{"newPassword": "myNewPassword"}' +// +// responses: +// '200': +// description: Password changed +// '400': +// description: Bad request +// '500': +// description: Internal server error +func ResetUserPassword(c *gin.Context){ + controllers.Post(c,"mongo") +} +// swagger:operation POST /users/password/forgot Authentication UserForgotPassword +// Forgot my password. +// Public endpoint to request a reset of a user's password (forgot my password). +// If the email is valid, an email with a reset token/link will be sent to the user. +// --- +// produces: +// - application/json +// parameters: +// - name: body +// in: body +// description: 'Mandatory: email.' +// type: string +// required: true +// example: '{"email": "user@test.com"}' +// +// responses: +// '200': +// description: request processed. If account exists, an email with a reset token is sent +// '400': +// description: Bad request +// '500': +// description: Internal server error +func UserForgotPassword(c *gin.Context){ + controllers.Post(c,"mongo") } \ No newline at end of file diff --git a/BFF/handlers/devices.go b/BFF/handlers/devices.go new file mode 100644 index 000000000..8a81b05e4 --- /dev/null +++ b/BFF/handlers/devices.go @@ -0,0 +1,97 @@ +package handlers + +import ( + "ogree-bff/controllers" + + "github.com/gin-gonic/gin" +) + +// swagger:operation GET /Devices Devices Devices +// Get Devices list +// +// --- +// parameters: +// - name: _key +// in: query +// description: Key of device +// required: false +// type: string +// - name: _name +// in: query +// description: Name of device +// required: false +// type: string +// - name: group_name +// in: query +// description: Group_name of device +// required: false +// type: string +// - name: serial +// in: query +// description: Serial number of device +// required: false +// type: string +// security: +// - Bearer: [] +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" + +func GetDevices(c *gin.Context) { + controllers.Get(c,"arango") +} + +// swagger:operation GET /Devices/ConnecteTo/{device} Devices GetDevicesConnectedTo +// Get Devices connected to a device +// +// --- +// parameters: +// - name: device +// in: path +// description: Key of device +// required: true +// type: string +// - name: _key +// in: query +// description: Filter devices by key +// required: false +// type: string +// - name: _name +// in: query +// description: Name of device +// required: false +// type: string +// - name: group_name +// in: query +// description: Group_name of device +// required: false +// type: string +// - name: serial +// in: query +// description: Serial number of device +// required: false +// type: string +// security: +// - Bearer: [] +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func GetDevicesConnectedTo(c *gin.Context) { + controllers.Get(c,"arango") +} \ No newline at end of file diff --git a/BFF/handlers/object.go b/BFF/handlers/object.go new file mode 100644 index 000000000..e7393c963 --- /dev/null +++ b/BFF/handlers/object.go @@ -0,0 +1,586 @@ +package handlers + +import ( + "ogree-bff/controllers" + + "github.com/gin-gonic/gin" +) + +// swagger:operation POST /{entity} Objects CreateObject +// Creates an object of the given entity in the system. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: entity +// in: path +// description: 'Entity (same as category) of the object. Accepted values: sites, domains, +// buildings, rooms, racks, devices, acs, panels, +// cabinets, groups, corridors, +// room-templates, obj-templates, bldg-templates, stray-devices.' +// required: true +// type: string +// default: "sites" +// - name: body +// in: body +// required: true +// default: {} +// responses: +// '201': +// description: 'Created. A response body will be returned with +// a meaningful message.' +// '400': +// description: 'Bad request. A response body with an error +// message will be returned.' +func CreateObject(c *gin.Context){ + controllers.Post(c,"mongo") +} + +// swagger:operation GET /objects/{hierarchyName} Objects GetGenericObject +// Get an object from any entity. +// Gets an object from any of the physical entities with no need to specify it. +// The hierarchyName must be provided in the URL as a parameter. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: hierarchyName +// in: path +// description: hierarchyName of the object +// required: true +// - name: fieldOnly +// in: query +// description: 'specify which object field to show in response. +// Multiple fieldOnly can be added. An invalid field is simply ignored.' +// - name: startDate +// in: query +// description: 'filter objects by lastUpdated >= startDate. +// Format: yyyy-mm-dd' +// - name: endDate +// in: query +// description: 'filter objects by lastUpdated <= endDate. +// Format: yyyy-mm-dd' +// responses: +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: Not Found. An error message will be returned. +func GetGenericObject(c *gin.Context){ + controllers.Get(c,"mongo") +} +// swagger:operation GET /{entity}/{IdOrHierarchyName} Objects GetEntity +// Gets an Object of the given entity. +// The ID or hierarchy name must be provided in the URL parameter. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: entity +// in: path +// description: 'Entity (same as category) of the object. Accepted values: sites, domains, +// buildings, rooms, racks, devices, acs, panels, +// cabinets, groups, corridors, +// room-templates, obj-templates, bldg-templates, stray-devices.' +// required: true +// type: string +// default: "sites" +// - name: IdOrHierarchyName +// in: path +// description: 'ID or hierarchy name of desired object. +// For templates the slug is the ID.' +// required: true +// type: string +// default: "siteA" +// - name: fieldOnly +// in: query +// description: 'specify which object field to show in response. +// Multiple fieldOnly can be added. An invalid field is simply ignored.' +// - name: startDate +// in: query +// description: 'filter objects by lastUpdated >= startDate. +// Format: yyyy-mm-dd' +// - name: endDate +// in: query +// description: 'filter objects by lastUpdated <= endDate. +// Format: yyyy-mm-dd' +// responses: +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '400': +// description: Bad request. An error message will be returned. +// '404': +// description: Not Found. An error message will be returned. +func GetEntity(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation GET /{entity} Objects GetAllEntities +// Gets all present objects for specified entity (category). +// Returns JSON body with all specified objects of type. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: entity +// in: path +// description: 'Entity (same as category) of the object. Accepted values: sites, domains, +// buildings, rooms, racks, devices, acs, panels, +// cabinets, groups, corridors, +// room-templates, obj-templates, bldg-templates, stray-devices' +// required: true +// type: string +// default: "sites" +// - name: fieldOnly +// in: query +// description: 'specify which object field to show in response. +// Multiple fieldOnly can be added. An invalid field is simply ignored.' +// - name: startDate +// in: query +// description: 'filter objects by lastUpdated >= startDate. +// Format: yyyy-mm-dd' +// - name: endDate +// in: query +// description: 'filter objects by lastUpdated <= endDate. +// Format: yyyy-mm-dd' +// +// responses: +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: Nothing Found. An error message will be returned. +func GetAllEntities(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation DELETE /{entity}/{IdOrHierarchyName} Objects DeleteObject +// Deletes an Object in the system. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: entity +// in: path +// description: 'Entity (same as category) of the object. Accepted values: sites, domains, +// buildings, rooms, racks, devices, acs, panels, +// cabinets, groups, corridors, +// room-templates, obj-templates, bldg-templates, stray-devices.' +// required: true +// type: string +// default: "sites" +// - name: IdOrHierarchyName +// in: path +// description: 'ID or hierarchy name of desired object. +// For templates the slug is the ID.' +// required: true +// type: string +// default: "siteA" +// +// responses: +// '204': +// description: 'Successfully deleted object. +// No response body will be returned' +// '404': +// description: Not found. An error message will be returned +func DeleteObject(c *gin.Context){ + controllers.Delete(c,"mongo") +} + +// swagger:operation PATCH /{entity}/{IdOrHierarchyName} Objects PartialUpdateObject +// Partially update object. +// This is the preferred method for modifying data in the system. +// If you want to do a full data replace, please use PUT instead. +// If no data is effectively changed, an OK will still be returned. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: entity +// in: path +// description: 'Entity (same as category) of the object. Accepted values: sites, domains, +// buildings, rooms, racks, devices, acs, panels, +// cabinets, groups, corridors, +// room-templates, obj-templates, bldg-templates, stray-devices.' +// required: true +// type: string +// default: "sites" +// - name: IdOrHierarchyName +// in: path +// description: 'ID or hierarchy name of desired object. +// For templates the slug is the ID.' +// required: true +// type: string +// default: "siteA" +// +// responses: +// '200': +// description: 'Updated. A response body will be returned with +// a meaningful message.' +// '400': +// description: Bad request. An error message will be returned. +// '404': +// description: Not Found. An error message will be returned. +func PartialUpdateObject(c *gin.Context){ + controllers.Patch(c,"mongo") +} + +// swagger:operation PUT /{objs}/{IdOrHierarchyName} Objects UpdateObject +// Completely update object. +// This method will replace the existing data with the JSON +// received, thus fully replacing the data. If you do not +// want to do this, please use PATCH. +// If no data is effectively changed, an OK will still be returned. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: entity +// in: path +// description: 'Entity (same as category) of the object. Accepted values: sites, domains, +// buildings, rooms, racks, devices, acs, panels, +// cabinets, groups, corridors, +// room-templates, obj-templates, bldg-templates, stray-devices.' +// required: true +// type: string +// default: "sites" +// - name: IdOrHierarchyName +// in: path +// description: 'ID or hierarchy name of desired object. +// For templates the slug is the ID.' +// required: true +// type: string +// default: "siteA" +// +// responses: +// '200': +// description: 'Updated. A response body will be returned with +// a meaningful message.' +// '400': +// description: Bad request. An error message will be returned. +// '404': +// description: Not Found. An error message will be returned. +func UpdateObject(c *gin.Context){ + controllers.Put(c,"mongo") +} + +// swagger:operation GET /{entity}? Objects GetEntityByQuery +// Gets an object filtering by attribute. +// Gets an Object using any attribute (with the exception of description) +// via query in the system +// The attributes are in the form {attr}=xyz&{attr1}=abc +// And any combination can be used given that at least 1 is provided. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: entity +// in: path +// description: 'Entity (same as category) of the object. Accepted values: sites, domains, +// buildings, rooms, racks, devices, acs, panels, +// cabinets, groups, corridors, +// room-templates, obj-templates, bldg-templates, stray-devices.' +// required: true +// type: string +// default: "sites" +// - name: fieldOnly +// in: query +// description: 'specify which object field to show in response. +// Multiple fieldOnly can be added. An invalid field is simply ignored.' +// - name: startDate +// in: query +// description: 'filter objects by lastUpdated >= startDate. +// Format: yyyy-mm-dd' +// - name: endDate +// in: query +// description: 'filter objects by lastUpdated <= endDate. +// Format: yyyy-mm-dd' +// - name: attributes +// in: query +// description: 'Any other object attributes can be queried. +// Replace attributes here by the name of the attribute followed by its value.' +// required: false +// type: string +// default: domain=DemoDomain +// example: vendor=ibm ; name=siteA ; orientation=front +// +// responses: +// '204': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: Not found. An error message will be returned. +func GetEntityByQuery(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation GET /tempunits/{IdOrHierarchyName} Objects GetTempUnit +// Gets the temperatureUnit attribute of the parent site of given object. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: IdOrHierarchyName +// in: path +// description: 'ID or hierarchy name of desired object. +// For templates the slug is the ID.' +// required: true +// type: string +// default: "siteA" +// responses: +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: 'Nothing Found. An error message will be returned.' +func GetTempUnit(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation GET /{entity}/{id}/{subent} Objects GetEntitiesOfAncestor +// Obtain all objects 2 levels lower in the system. +// For Example: /api/sites/{id}/buildings +// Will return all buildings of a site +// Returns JSON body with all subobjects under the Object +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: entity +// in: query +// description: 'Indicates the entity. Only values of "sites", +// "buildings", "rooms" are acceptable' +// required: true +// type: string +// default: "sites" +// - name: ID +// in: query +// description: ID of object +// required: true +// type: int +// default: 999 +// - name: subent +// in: query +// description: Objects which 2 are levels lower in the hierarchy. +// required: true +// type: string +// default: buildings +// responses: +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: Nothing Found. An error message will be returned. +func GetEntitiesOfAncestor(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation GET /{entity}/{IdOrHierarchyName}/all Objects GetEntityHierarchy +// Get object and all its children. +// Returns JSON body with all subobjects under the Object. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: entity +// in: path +// description: 'Entity (same as category) of the object. Accepted values: sites, domains, +// buildings, rooms, racks, devices, acs, panels, +// cabinets, groups, corridors, +// room-templates, obj-templates, bldg-templates, stray-devices.' +// required: true +// type: string +// default: "sites" +// - name: IdOrHierarchyName +// in: path +// description: 'ID or hierarchy name of desired object. +// For templates the slug is the ID.' +// required: true +// type: string +// default: "siteA" +// - name: limit +// in: query +// description: 'Limits the level of hierarchy for retrieval. if not +// specified for devices then the default value is maximum. +// Example: /api/devices/{id}/all?limit=2' +// required: false +// type: string +// default: 1 +// - name: fieldOnly +// in: query +// description: 'specify which object field to show in response. +// Multiple fieldOnly can be added. An invalid field is simply ignored.' +// - name: startDate +// in: query +// description: 'filter objects by lastUpdated >= startDate. +// Format: yyyy-mm-dd' +// - name: endDate +// in: query +// description: 'filter objects by lastUpdated <= endDate. +// Format: yyyy-mm-dd' +// responses: +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: Nothing Found. An error message will be returned. +func GetEntityHierarchy(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation GET /hierarchy Objects GetCompleteHierarchy +// Returns system complete hierarchy. +// Return is arranged by relationship (father:[children]) +// and category (category:[objects]), starting with "Root":[sites]. +// User permissions apply. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// responses: +// '200': +// description: 'Request is valid.' +// '500': +// description: Server error. + +func GetCompleteHierarchy(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation GET /hierarchy/attributes Objects GetCompleteHierarchyAttrs +// Returns attributes of all objects. +// Return is arranged by hierarchyName (objHierarchyName:{attributes}). +// User permissions apply. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// responses: +// '200': +// description: 'Request is valid.' +// '500': +// description: Server error. +func GetCompleteHierarchyAttrs(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation GET /{firstEntity}/{id}/{HierarchalPath} Objects GetEntitiesUsingNamesOfParents +// Get an object with its full hierarchal path. +// The path should begin with an entity name (firstEntity) and the ID of an object of this entity +// followed by a hierarchal path until the desired objet, that is, +// a sequence of entity names (category) and object names. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: firstEntity +// in: query +// description: 'Root entity followed by an id. Can be: sites, buildings, rooms, racks or devices' +// required: true +// type: string +// default: "sites" +// - name: id +// in: path +// description: 'id of object of firstEntity' +// required: true +// type: string +// default: "123" +// - name: HierarchalPath +// in: path +// description: 'Hierarchal path to desired object.' +// required: true +// type: string +// example: '/api/sites/{id}/buildings/{building_name} ; +// /api/sites/{id}/buildings/{building_name}/rooms/{room_name} ; +// /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/acs/{ac_name} ; +// /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/corridors/{corridor_name} ; +// /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/panels/{panel_name} ; +// /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/groups/{group_name} ; +// /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/racks/{rack_name}/devices/{device_name} ; +// /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/racks/{rack_name} ; +// /api/buildings/{id}/rooms/{room_name} ; +// /api/buildings/{id}/rooms/{room_name}/acs/{ac_name} ; +// /api/buildings/{id}/rooms/{room_name}/corridors/{corridor_name} ; +// /api/buildings/{id}/rooms/{room_name}/panels/{panel_name} ; +// /api/buildings/{id}/rooms/{room_name}/groups/{group_name} ; +// /api/buildings/{id}/rooms/{room_name}/rack/{rack_name} ; +// /api/buildings/{id}/rooms/{room_name}/racks/{rack_name}/devices/{device_name} ; +// /api/rooms/{id}/acs/{ac_name} ; +// /api/rooms/{id}/corridors/{corridor_name} ; +// /api/rooms/{id}/panels/{panel_name} ; +// /api/rooms/{id}/groups/{group_name} ; +// /api/rooms/{id}/racks/{rack_name}/devices/{device_name} ; +// /api/racks/{id}/devices/{device_name} ; +// /api/devices/{id}/devices/{device_name} ;' +// default: "/buildings/BuildingB/rooms/RoomA" +// responses: +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: Not Found. An error message will be returned. + +func GetEntitiesUsingNamesOfParents(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation POST /validate/{entity} Objects ValidateObject +// Checks the received data and verifies if the object can be created in the system. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: entity +// in: path +// description: 'Entity (same as category) of the object. Accepted values: sites, domains, +// buildings, rooms, racks, devices, acs, panels, +// cabinets, groups, corridors, +// room-templates, obj-templates, bldg-templates, stray-devices.' +// required: true +// type: string +// default: "sites" +// - name: body +// in: body +// required: true +// default: {} +// responses: +// '200': +// description: 'Createable. A response body will be returned with +// a meaningful message.' +// '400': +// description: 'Bad request. A response body with an error +// message will be returned.' +// '404': +// description: Not Found. An error message will be returned. +func ValidateObject(c *gin.Context){ + controllers.Post(c,"mongo") +} \ No newline at end of file diff --git a/BFF/handlers/organization.go b/BFF/handlers/organization.go new file mode 100644 index 000000000..99a913b3b --- /dev/null +++ b/BFF/handlers/organization.go @@ -0,0 +1,183 @@ +package handlers + +import ( + "ogree-bff/controllers" + + "github.com/gin-gonic/gin" +) + +// swagger:operation POST /users Organization CreateAccount +// Create a new user user. +// Create an account with email and password credentials, it returns +// a JWT key to use with the API. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: body +// in: body +// description: 'Mandatory: email, password and roles. Optional: name. +// Roles is an object with domains as keys and roles as values. +// Possible roles: manager, user and viewer' +// required: true +// format: object +// example: '{"name": "John Doe", "roles": {"*": "manager"}, "email": "user@test.com", "password": "secret123"}' +// +// responses: +// '201': +// description: New account created +// '400': +// description: Bad request +// '403': +// description: User not authorised to create an account +// '500': +// description: Internal server error +func CreateAccount(c *gin.Context){ + controllers.Post(c,"mongo") +} +// swagger:operation POST /users/bulk Organization CreateBulk +// Create multiples users with one request. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: body +// in: body +// description: 'An array of users. Same mandatory and optional parameters as user apply, +// except for password. If not provided, one will be automatically created by the API.' +// required: true +// format: object +// example: '[{"name": "John Doe", "roles": {"*": "manager"}, "email": "user@test.com"}]' +// +// responses: +// '200': +// description: Request processed, check response body for results +// '400': +// description: Bad request +// '500': +// description: Internal server error +func CreateBulk(c *gin.Context){ + controllers.Post(c,"mongo") +} + +// swagger:operation GET /users Organization GetAllAccounts +// Get a list of users that the caller is allowed to see. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// responses: +// '200': +// description: Return all possible users +// '500': +// description: Internal server error +func GetAllAccounts(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation DELETE /users/{userid} Organization RemoveAccount +// Remove the specified user account. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: userid +// in: path +// description: 'The ID of the user to delete' +// required: true +// type: string +// example: "someUserId" +// responses: +// '200': +// description: User removed +// '400': +// description: User ID not valid or not found +// '403': +// description: Caller not authorised to delete this user +// '500': +// description: Internal server error +func RemoveAccount(c *gin.Context){ + controllers.Delete(c,"mongo") +} + +// swagger:operation PATCH /users/{userid} Organization ModifyUserRoles +// Modify user permissions: domain and role. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: userid +// in: path +// description: 'The ID of the user to modify roles' +// required: true +// type: string +// example: "someUserId" +// - name: roles +// in: body +// description: An object with domains as keys and roles as values +// type: json +// required: true +// example: '{"roles": {"*": "manager"}}' +// +// responses: +// '200': +// description: User roles modified +// '400': +// description: Bad request +// '403': +// description: Caller not authorised to modify this user +// '500': +// description: Internal server error +func ModifyUserRoles(c *gin.Context){ + controllers.Patch(c,"mongo") +} + +// swagger:operation POST /domains/bulk Organization CreateBulkDomain +// Create multiple domains in a single request. +// An array of domains should be provided in the body. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: body +// in: body +// required: true +// default: [{}] +// responses: +// '200': +// description: 'Request processed. Check the response body +// for individual results for each of the sent domains' +// '400': +// description: 'Bad format: body is not a valid list of domains.' +func CreateBulkDomain(c *gin.Context){ + controllers.Post(c,"mongo") +} + +// swagger:operation GET /hierarchy/domains Organization GetCompleteDomainHierarchy +// Returns domain complete hierarchy. +// Return is arranged by relationship (father:[children]), +// starting with "Root":[root domains]. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// responses: +// '200': +// description: 'Request is valid.' +// '500': +// description: Server error. +func GetCompleteDomainHierarchy(c *gin.Context){ + controllers.Get(c,"mongo") +} \ No newline at end of file diff --git a/BFF/main.go b/BFF/main.go index a946fb967..f080a7010 100644 --- a/BFF/main.go +++ b/BFF/main.go @@ -3,7 +3,7 @@ // title: Awsome API // Schemes: http, https // Host: -// BasePath: /api/v1 +// BasePath: /api // Consumes: // - application/json // Produces: @@ -36,13 +36,14 @@ func main() { return } } - - ArangoUrl := os.Getenv("ARANGO_URL") + BFF_PORT := os.Getenv("BFF_PORT") + arangoAPI := os.Getenv("ARANGO_API") + mongoAPI := os.Getenv("MONGO_API") apiList := []models.API { - {Name: "Arango", URL: ArangoUrl}, + {Name: "arango", URL: arangoAPI}, + {Name: "mongo", URL: mongoAPI}, } - - + fmt.Println(apiList) router := services.InitRouter(apiList,env) - router.Run(":8080") + router.Run(":"+BFF_PORT) } diff --git a/BFF/models/auth.go b/BFF/models/auth.go index b1395bb58..cd0fe068d 100644 --- a/BFF/models/auth.go +++ b/BFF/models/auth.go @@ -3,9 +3,9 @@ package models // swagger:model LoginInput type LoginInput struct { - // username - // in: username - Username string `json:"username" binding:"required"` + // email + // in: email + Email string `json:"email" binding:"required"` // username // in: password Password string `json:"password" binding:"required"` @@ -13,7 +13,7 @@ type LoginInput struct { type User struct { ID uint `json:"id"` - Username string `json:"username" binding:"required"` + Email string `json:"email" binding:"required"` Password string `json:"password" binding:"required"` } diff --git a/BFF/models/http.go b/BFF/models/http.go index 97e91c1d7..3a6f8df07 100644 --- a/BFF/models/http.go +++ b/BFF/models/http.go @@ -18,5 +18,5 @@ type SuccessResponse struct { type Message struct { StatusCode int `json:"statuscode"` - Message string `json:"message"` + Message interface{} `json:"message"` } diff --git a/BFF/services/router.go b/BFF/services/router.go index e035bfeeb..d3650f0e1 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -1,12 +1,13 @@ package services import ( - "ogree-bff/handlers" - "ogree-bff/utils/token" + "net/http" + "ogree-bff/handlers" "ogree-bff/models" + "ogree-bff/utils/token" -// driver "github.com/arangodb/go-driver" + // driver "github.com/arangodb/go-driver" "github.com/gin-gonic/gin" ) @@ -24,23 +25,105 @@ func JwtAuthMiddleware() gin.HandlerFunc { } } + +func APIMiddleware(apiList []models.API) gin.HandlerFunc { + return func (c *gin.Context){ + for _, api := range apiList { + c.Set(api.Name,api.URL) + + } + c.Next() + + } + +} +func initDevices(protected, unprotected *gin.RouterGroup){ + + protected.GET("/Devices",handlers.GetDevices) + protected.GET("/Devices/ConnecteTo/:key",handlers.GetDevicesConnectedTo) +} + +func initAuth(protected, unprotected *gin.RouterGroup){ + + protected.GET("/token/valid",handlers.ValidToken) + protected.POST("/users/password/reset",handlers.ResetUserPassword) + protected.POST("/users/password/change",handlers.ModifyUserPassword) + + unprotected.POST("/login",handlers.Login) + unprotected.POST("/users/password/forgot",handlers.UserForgotPassword) +} + +func initOrganization(protected, unprotected *gin.RouterGroup){ + protected.POST("/users",handlers.CreateAccount) + protected.POST("/users/bulk",handlers.CreateBulk) + protected.GET("/users",handlers.GetAllAccounts) + protected.DELETE("/users/:user",handlers.RemoveAccount) + protected.PATCH("/users/:user",handlers.ModifyUserRoles) + protected.POST("/domains/bulk",handlers.CreateBulkDomain) + protected.GET("/hierarchy/domains",handlers.GetCompleteDomainHierarchy) +} + +func initObjects(protected, unprotected *gin.RouterGroup){ + + protected.GET("/:entity",handlers.GetAllEntities) + protected.POST("/:entity",handlers.CreateObject) + + protected.GET("/objects/:hierarchyName",handlers.GetGenericObject) + + protected.GET("/:entity/:id",handlers.GetEntity) + protected.DELETE("/:entity/:id",handlers.DeleteObject) + protected.PATCH("/:entity/:id",handlers.PartialUpdateObject) + protected.PUT("/:entity/:id",handlers.UpdateObject) + protected.GET("/:entity/:id/all",handlers.GetEntityHierarchy) + + protected.GET("/tempunits/:id",handlers.GetTempUnit) + + protected.GET("/:entity/:id/:subent",handlers.GetEntitiesOfAncestor) + + + protected.GET("/hierarchy",handlers.GetCompleteHierarchy) + protected.GET("/hierarchy/attributes",handlers.GetCompleteHierarchyAttrs) + + //protected.GET("/:entity/:id/:HierarchalPath",handlers.GetEntitiesUsingNamesOfParents) + + protected.POST("/validate/:entity",handlers.ValidateObject) + + +} + + func InitRouter(apiList []models.API,env string ) *gin.Engine { if env == "production" { gin.SetMode(gin.ReleaseMode) } + router := gin.Default() - proteted := router.Group("/api/v1") - proteted.Use(JwtAuthMiddleware()) + protected := router.Group("/api") + protected.Use(JwtAuthMiddleware()) + protected.Use(APIMiddleware(apiList)) + + unprotected := router.Group("/api") + unprotected.Use(APIMiddleware(apiList)) + + initDevices(protected,unprotected) + initAuth(protected,unprotected) + initOrganization(protected,unprotected) + initObjects(protected,unprotected) + - router.POST("/api/v1/Login",handlers.Login) - router.GET("/api/v1/health",func(c *gin.Context){ + //init healthcheck route + unprotected.GET("/health",func(c *gin.Context){ c.String(http.StatusAccepted,"") }) + swagger := handlers.SwaggerHandler() router.Use(gin.WrapH(swagger)) + + + return router } diff --git a/BFF/swagger.yaml b/BFF/swagger.yaml index d6e06680e..13362a0a1 100644 --- a/BFF/swagger.yaml +++ b/BFF/swagger.yaml @@ -1,4 +1,4 @@ -basePath: /api/v1 +basePath: /api consumes: - application/json definitions: @@ -14,18 +14,18 @@ definitions: x-go-package: ogree-bff/models LoginInput: properties: + email: + description: |- + email + in: email + type: string + x-go-name: Email password: description: |- username in: password type: string x-go-name: Password - username: - description: |- - username - in: username - type: string - x-go-name: Username type: object x-go-package: ogree-bff/models SuccessLogin: @@ -49,29 +49,838 @@ info: title: 'Ogree BFF:' version: 1.0.0 paths: - /Login: + /{entity}: + get: + description: Returns JSON body with all specified objects of type. + operationId: GetAllEntities + parameters: + - default: sites + description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices' + in: path + name: entity + required: true + type: string + - description: specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored. + in: query + name: fieldOnly + - description: 'filter objects by lastUpdated >= startDate. Format: yyyy-mm-dd' + in: query + name: startDate + - description: 'filter objects by lastUpdated <= endDate. Format: yyyy-mm-dd' + in: query + name: endDate + produces: + - application/json + responses: + "200": + description: Found. A response body will be returned with a meaningful message. + "404": + description: Nothing Found. An error message will be returned. + security: + - Bearer: [] + summary: Gets all present objects for specified entity (category). + tags: + - Objects post: - description: Login to api - operationId: LoginToApi + operationId: CreateObject parameters: - - in: body + - default: sites + description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' + in: path + name: entity + required: true + type: string + - default: {} + in: body name: body - schema: - $ref: '#/definitions/LoginInput' - x-go-name: Body + required: true + produces: + - application/json + responses: + "201": + description: Created. A response body will be returned with a meaningful message. + "400": + description: Bad request. A response body with an error message will be returned. + security: + - Bearer: [] + summary: Creates an object of the given entity in the system. + tags: + - Objects + /{entity}/{IdOrHierarchyName}: + delete: + operationId: DeleteObject + parameters: + - default: sites + description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' + in: path + name: entity + required: true + type: string + - default: siteA + description: ID or hierarchy name of desired object. For templates the slug is the ID. + in: path + name: IdOrHierarchyName + required: true + type: string + produces: + - application/json + responses: + "204": + description: Successfully deleted object. No response body will be returned + "404": + description: Not found. An error message will be returned + security: + - Bearer: [] + summary: Deletes an Object in the system. + tags: + - Objects + get: + description: The ID or hierarchy name must be provided in the URL parameter. + operationId: GetEntity + parameters: + - default: sites + description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' + in: path + name: entity + required: true + type: string + - default: siteA + description: ID or hierarchy name of desired object. For templates the slug is the ID. + in: path + name: IdOrHierarchyName + required: true + type: string + - description: specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored. + in: query + name: fieldOnly + - description: 'filter objects by lastUpdated >= startDate. Format: yyyy-mm-dd' + in: query + name: startDate + - description: 'filter objects by lastUpdated <= endDate. Format: yyyy-mm-dd' + in: query + name: endDate + produces: + - application/json + responses: + "200": + description: Found. A response body will be returned with a meaningful message. + "400": + description: Bad request. An error message will be returned. + "404": + description: Not Found. An error message will be returned. + security: + - Bearer: [] + summary: Gets an Object of the given entity. + tags: + - Objects + patch: + description: |- + This is the preferred method for modifying data in the system. + If you want to do a full data replace, please use PUT instead. + If no data is effectively changed, an OK will still be returned. + operationId: PartialUpdateObject + parameters: + - default: sites + description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' + in: path + name: entity + required: true + type: string + - default: siteA + description: ID or hierarchy name of desired object. For templates the slug is the ID. + in: path + name: IdOrHierarchyName + required: true + type: string + produces: + - application/json + responses: + "200": + description: Updated. A response body will be returned with a meaningful message. + "400": + description: Bad request. An error message will be returned. + "404": + description: Not Found. An error message will be returned. + security: + - Bearer: [] + summary: Partially update object. + tags: + - Objects + /{entity}/{IdOrHierarchyName}/all: + get: + description: Returns JSON body with all subobjects under the Object. + operationId: GetEntityHierarchy + parameters: + - default: sites + description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' + in: path + name: entity + required: true + type: string + - default: siteA + description: ID or hierarchy name of desired object. For templates the slug is the ID. + in: path + name: IdOrHierarchyName + required: true + type: string + - default: 1 + description: 'Limits the level of hierarchy for retrieval. if not specified for devices then the default value is maximum. Example: /api/devices/{id}/all?limit=2' + in: query + name: limit + type: string + - description: specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored. + in: query + name: fieldOnly + - description: 'filter objects by lastUpdated >= startDate. Format: yyyy-mm-dd' + in: query + name: startDate + - description: 'filter objects by lastUpdated <= endDate. Format: yyyy-mm-dd' + in: query + name: endDate + produces: + - application/json + responses: + "200": + description: Found. A response body will be returned with a meaningful message. + "404": + description: Nothing Found. An error message will be returned. + security: + - Bearer: [] + summary: Get object and all its children. + tags: + - Objects + /{entity}/{id}/{subent}: + get: + description: |- + For Example: /api/sites/{id}/buildings + Will return all buildings of a site + Returns JSON body with all subobjects under the Object + operationId: GetEntitiesOfAncestor + parameters: + - default: sites + description: Indicates the entity. Only values of "sites", "buildings", "rooms" are acceptable + in: query + name: entity + required: true + type: string + - default: 999 + description: ID of object + in: query + name: ID + required: true + type: int + - default: buildings + description: Objects which 2 are levels lower in the hierarchy. + in: query + name: subent + required: true + type: string + produces: + - application/json + responses: + "200": + description: Found. A response body will be returned with a meaningful message. + "404": + description: Nothing Found. An error message will be returned. + security: + - Bearer: [] + summary: Obtain all objects 2 levels lower in the system. + tags: + - Objects + /{entity}?: + get: + description: |- + Gets an Object using any attribute (with the exception of description) + via query in the system + The attributes are in the form {attr}=xyz&{attr1}=abc + And any combination can be used given that at least 1 is provided. + operationId: GetEntityByQuery + parameters: + - default: sites + description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' + in: path + name: entity + required: true + type: string + - description: specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored. + in: query + name: fieldOnly + - description: 'filter objects by lastUpdated >= startDate. Format: yyyy-mm-dd' + in: query + name: startDate + - description: 'filter objects by lastUpdated <= endDate. Format: yyyy-mm-dd' + in: query + name: endDate + - default: domain=DemoDomain + description: Any other object attributes can be queried. Replace attributes here by the name of the attribute followed by its value. + example: vendor=ibm ; name=siteA ; orientation=front + in: query + name: attributes + type: string + produces: + - application/json + responses: + "204": + description: Found. A response body will be returned with a meaningful message. + "404": + description: Not found. An error message will be returned. + security: + - Bearer: [] + summary: Gets an object filtering by attribute. + tags: + - Objects + /{firstEntity}/{id}/{HierarchalPath}: + get: + description: |- + The path should begin with an entity name (firstEntity) and the ID of an object of this entity + followed by a hierarchal path until the desired objet, that is, + a sequence of entity names (category) and object names. + operationId: GetEntitiesUsingNamesOfParents + parameters: + - default: sites + description: 'Root entity followed by an id. Can be: sites, buildings, rooms, racks or devices' + in: query + name: firstEntity + required: true + type: string + - default: "123" + description: id of object of firstEntity + in: path + name: id + required: true + type: string + - default: /buildings/BuildingB/rooms/RoomA + description: Hierarchal path to desired object. + example: /api/sites/{id}/buildings/{building_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/acs/{ac_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/corridors/{corridor_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/panels/{panel_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/groups/{group_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/racks/{rack_name}/devices/{device_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/racks/{rack_name} ; /api/buildings/{id}/rooms/{room_name} ; /api/buildings/{id}/rooms/{room_name}/acs/{ac_name} ; /api/buildings/{id}/rooms/{room_name}/corridors/{corridor_name} ; /api/buildings/{id}/rooms/{room_name}/panels/{panel_name} ; /api/buildings/{id}/rooms/{room_name}/groups/{group_name} ; /api/buildings/{id}/rooms/{room_name}/rack/{rack_name} ; /api/buildings/{id}/rooms/{room_name}/racks/{rack_name}/devices/{device_name} ; /api/rooms/{id}/acs/{ac_name} ; /api/rooms/{id}/corridors/{corridor_name} ; /api/rooms/{id}/panels/{panel_name} ; /api/rooms/{id}/groups/{group_name} ; /api/rooms/{id}/racks/{rack_name}/devices/{device_name} ; /api/racks/{id}/devices/{device_name} ; /api/devices/{id}/devices/{device_name} ; + in: path + name: HierarchalPath + required: true + type: string + produces: + - application/json + responses: + "200": + description: Found. A response body will be returned with a meaningful message. + "404": + description: Not Found. An error message will be returned. + security: + - Bearer: [] + summary: Get an object with its full hierarchal path. + tags: + - Objects + /{objs}/{IdOrHierarchyName}: + put: + description: |- + This method will replace the existing data with the JSON + received, thus fully replacing the data. If you do not + want to do this, please use PATCH. + If no data is effectively changed, an OK will still be returned. + operationId: UpdateObject + parameters: + - default: sites + description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' + in: path + name: entity + required: true + type: string + - default: siteA + description: ID or hierarchy name of desired object. For templates the slug is the ID. + in: path + name: IdOrHierarchyName + required: true + type: string + produces: + - application/json + responses: + "200": + description: Updated. A response body will be returned with a meaningful message. + "400": + description: Bad request. An error message will be returned. + "404": + description: Not Found. An error message will be returned. + security: + - Bearer: [] + summary: Completely update object. + tags: + - Objects + /Devices: + get: + description: Get Devices list + operationId: Devices + parameters: + - description: Key of device + in: query + name: _key + type: string + - description: Name of device + in: query + name: _name + type: string + - description: Group_name of device + in: query + name: group_name + type: string + - description: Serial number of device + in: query + name: serial + type: string + responses: + "200": + description: successful + schema: + items: + $ref: '#/definitions/SuccessResponse' + "500": + description: Error + schema: + items: + $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] + tags: + - Devices + /Devices/ConnecteTo/{device}: + get: + description: Get Devices connected to a device + operationId: GetDevicesConnectedTo + parameters: + - description: Key of device + in: path + name: device + required: true + type: string + - description: Filter devices by key + in: query + name: _key + type: string + - description: Name of device + in: query + name: _name + type: string + - description: Group_name of device + in: query + name: group_name + type: string + - description: Serial number of device + in: query + name: serial + type: string responses: "200": description: successful schema: items: - $ref: '#/definitions/SuccessLogin' + $ref: '#/definitions/SuccessResponse' "500": description: Error schema: items: $ref: '#/definitions/ErrorResponse' + security: + - Bearer: [] + tags: + - Devices + /domains/bulk: + post: + description: An array of domains should be provided in the body. + operationId: CreateBulkDomain + parameters: + - default: + - {} + in: body + name: body + required: true + produces: + - application/json + responses: + "200": + description: Request processed. Check the response body for individual results for each of the sent domains + "400": + description: 'Bad format: body is not a valid list of domains.' + security: + - Bearer: [] + summary: Create multiple domains in a single request. + tags: + - Organization + /hierarchy: + get: + description: |- + Return is arranged by relationship (father:[children]) + and category (category:[objects]), starting with "Root":[sites]. + User permissions apply. + operationId: GetCompleteHierarchy + produces: + - application/json + responses: + "200": + description: Request is valid. + "500": + description: Server error. + security: + - Bearer: [] + summary: Returns system complete hierarchy. + tags: + - Objects + /hierarchy/attributes: + get: + description: |- + Return is arranged by hierarchyName (objHierarchyName:{attributes}). + User permissions apply. + operationId: GetCompleteHierarchyAttrs + produces: + - application/json + responses: + "200": + description: Request is valid. + "500": + description: Server error. + security: + - Bearer: [] + summary: Returns attributes of all objects. + tags: + - Objects + /hierarchy/domains: + get: + description: |- + Return is arranged by relationship (father:[children]), + starting with "Root":[root domains]. + operationId: GetCompleteDomainHierarchy + produces: + - application/json + responses: + "200": + description: Request is valid. + "500": + description: Server error. + security: + - Bearer: [] + summary: Returns domain complete hierarchy. + tags: + - Organization + /login: + post: + description: |- + Create a new JWT Key. This can also be used to verify credentials + The authorize and 'Try it out' buttons don't work + operationId: Authenticate + parameters: + - description: 'Mandatory: email and password.' + example: '{"email": "user@test.com", "password": "secret123"}' + format: object + in: body + name: body + required: true + produces: + - application/json + responses: + "200": + description: Authenticated + "400": + description: Bad request + "500": + description: Internal server error + summary: Generates a new JWT Key for the client. + tags: + - Authentication + /objects/{hierarchyName}: + get: + description: |- + Gets an object from any of the physical entities with no need to specify it. + The hierarchyName must be provided in the URL as a parameter. + operationId: GetGenericObject + parameters: + - description: hierarchyName of the object + in: path + name: hierarchyName + required: true + - description: specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored. + in: query + name: fieldOnly + - description: 'filter objects by lastUpdated >= startDate. Format: yyyy-mm-dd' + in: query + name: startDate + - description: 'filter objects by lastUpdated <= endDate. Format: yyyy-mm-dd' + in: query + name: endDate + produces: + - application/json + responses: + "200": + description: Found. A response body will be returned with a meaningful message. + "404": + description: Not Found. An error message will be returned. + security: + - Bearer: [] + summary: Get an object from any entity. + tags: + - Objects + /tempunits/{IdOrHierarchyName}: + get: + operationId: GetTempUnit + parameters: + - default: siteA + description: ID or hierarchy name of desired object. For templates the slug is the ID. + in: path + name: IdOrHierarchyName + required: true + type: string + produces: + - application/json + responses: + "200": + description: Found. A response body will be returned with a meaningful message. + "404": + description: Nothing Found. An error message will be returned. + security: + - Bearer: [] + summary: Gets the temperatureUnit attribute of the parent site of given object. + tags: + - Objects + /token/valid: + get: + operationId: VerifyToken + produces: + - application/json + responses: + "200": + description: Token is valid. + "403": + description: Unauthorized + "500": + description: Internal server error + security: + - Bearer: [] + summary: Verify if token sent in the header is valid. + tags: + - Authentication + /users: + get: + operationId: GetAllAccounts + produces: + - application/json + responses: + "200": + description: Return all possible users + "500": + description: Internal server error + security: + - Bearer: [] + summary: Get a list of users that the caller is allowed to see. + tags: + - Organization + post: + description: |- + Create an account with email and password credentials, it returns + a JWT key to use with the API. + operationId: CreateAccount + parameters: + - description: 'Mandatory: email, password and roles. Optional: name. Roles is an object with domains as keys and roles as values. Possible roles: manager, user and viewer' + example: '{"name": "John Doe", "roles": {"*": "manager"}, "email": "user@test.com", "password": "secret123"}' + format: object + in: body + name: body + required: true + produces: + - application/json + responses: + "201": + description: New account created + "400": + description: Bad request + "403": + description: User not authorised to create an account + "500": + description: Internal server error + security: + - Bearer: [] + summary: Create a new user user. + tags: + - Organization + /users/{userid}: + delete: + operationId: RemoveAccount + parameters: + - description: The ID of the user to delete + example: someUserId + in: path + name: userid + required: true + type: string + produces: + - application/json + responses: + "200": + description: User removed + "400": + description: User ID not valid or not found + "403": + description: Caller not authorised to delete this user + "500": + description: Internal server error + security: + - Bearer: [] + summary: Remove the specified user account. + tags: + - Organization + patch: + operationId: ModifyUserRoles + parameters: + - description: The ID of the user to modify roles + example: someUserId + in: path + name: userid + required: true + type: string + - description: An object with domains as keys and roles as values + example: '{"roles": {"*": "manager"}}' + in: body + name: roles + required: true + type: json + produces: + - application/json + responses: + "200": + description: User roles modified + "400": + description: Bad request + "403": + description: Caller not authorised to modify this user + "500": + description: Internal server error + security: + - Bearer: [] + summary: 'Modify user permissions: domain and role.' + tags: + - Organization + /users/bulk: + post: + operationId: CreateBulk + parameters: + - description: An array of users. Same mandatory and optional parameters as user apply, except for password. If not provided, one will be automatically created by the API. + example: '[{"name": "John Doe", "roles": {"*": "manager"}, "email": "user@test.com"}]' + format: object + in: body + name: body + required: true + produces: + - application/json + responses: + "200": + description: Request processed, check response body for results + "400": + description: Bad request + "500": + description: Internal server error + security: + - Bearer: [] + summary: Create multiples users with one request. + tags: + - Organization + /users/password/change: + post: + operationId: ModifyUserPassword + parameters: + - description: 'Mandatory: currentPassword and newPassword.' + example: '{"currentPassword": "myOldPassword", "newPassword": "myNewPassword"}' + in: body + name: body + required: true + type: json + produces: + - application/json + responses: + "200": + description: Password changed + "400": + description: Bad request + "500": + description: Internal server error + security: + - Bearer: [] + summary: For logged in user to change its own password. + tags: + - Authentication + /users/password/forgot: + post: + description: |- + Public endpoint to request a reset of a user's password (forgot my password). + If the email is valid, an email with a reset token/link will be sent to the user. + operationId: UserForgotPassword + parameters: + - description: 'Mandatory: email.' + example: '{"email": "user@test.com"}' + in: body + name: body + required: true + type: string + produces: + - application/json + responses: + "200": + description: request processed. If account exists, an email with a reset token is sent + "400": + description: Bad request + "500": + description: Internal server error + summary: Forgot my password. + tags: + - Authentication + /users/password/reset: + post: + description: |- + For user that first called forgot enpoint to change its password. + A reset token generated by the forgot endpoint should be provided as the Authentication header. + operationId: ResetUserPassword + parameters: + - description: 'Mandatory: currentPassword and newPassword.' + example: '{"newPassword": "myNewPassword"}' + in: body + name: body + required: true + type: json + produces: + - application/json + responses: + "200": + description: Password changed + "400": + description: Bad request + "500": + description: Internal server error + security: + - Bearer: [] + summary: Reset password after forgot. + tags: + - Authentication + /validate/{entity}: + post: + operationId: ValidateObject + parameters: + - default: sites + description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' + in: path + name: entity + required: true + type: string + - default: {} + in: body + name: body + required: true + produces: + - application/json + responses: + "200": + description: Createable. A response body will be returned with a meaningful message. + "400": + description: Bad request. A response body with an error message will be returned. + "404": + description: Not Found. An error message will be returned. + security: + - Bearer: [] + summary: Checks the received data and verifies if the object can be created in the system. tags: - - Login + - Objects produces: - application/json schemes: diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index cf002a503..1bee2f266 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -12,7 +12,7 @@ services: - db_user=${COMPOSE_PROJECT_NAME} - db_pass=${CUSTOMER_API_PASSWORD} - db=${COMPOSE_PROJECT_NAME} - - token_password=yourSecretPasswordGoesHere + - token_password=myAwesomeApiSecret ports: - ${API_PORT}:3001 depends_on: @@ -48,6 +48,9 @@ services: - ${API_DOC_UI_PORT}:8080 environment: SWAGGER_JSON_URL: https://raw.githubusercontent.com/ditrit/OGrEE-Core/${IMAGE_TAG}/API/swagger.json + restart: on-failure:10 + depends_on: + - ogree_api ogree_webapp: build: From 980c6f9813aadefe284356c1dbae73e334dd1c44 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Tue, 8 Aug 2023 10:04:56 +0200 Subject: [PATCH 11/35] feat(bff): add flutterApp and about route to bff --- BFF/handlers/about.go | 38 +++++++++++ BFF/handlers/flutterApp.go | 122 +++++++++++++++++++++++++++++++++++ BFF/services/router.go | 13 ++++ BFF/swagger.yaml | 127 +++++++++++++++++++++++++++++++++++++ 4 files changed, 300 insertions(+) create mode 100644 BFF/handlers/about.go create mode 100644 BFF/handlers/flutterApp.go diff --git a/BFF/handlers/about.go b/BFF/handlers/about.go new file mode 100644 index 000000000..3ec2b2c24 --- /dev/null +++ b/BFF/handlers/about.go @@ -0,0 +1,38 @@ +package handlers + +import ( + "ogree-bff/controllers" + + "github.com/gin-gonic/gin" +) + +// swagger:operation GET /stats About GetStats +// Displays DB statistics. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// responses: +// '200': +// description: 'Request is valid.' +// '504': +// description: Server error. +func GetStats(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation GET /api/version About GetAPIVersion +// Gets the API version. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// responses: +// '200': +// description: 'OK. A response body will be returned with +// version details.' +func GetAPIVersion(c *gin.Context){ + controllers.Get(c,"mongo") +} \ No newline at end of file diff --git a/BFF/handlers/flutterApp.go b/BFF/handlers/flutterApp.go new file mode 100644 index 000000000..b457fd05e --- /dev/null +++ b/BFF/handlers/flutterApp.go @@ -0,0 +1,122 @@ +package handlers + +import ( + "ogree-bff/controllers" + + "github.com/gin-gonic/gin" +) + +// swagger:operation GET /projects FlutterApp GetProjects +// Get a list of projects for the specified user. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: user +// in: query +// description: 'Email of the user whose projects are being requested. +// Example: /api/projects?user=user@test.com' +// required: false +// type: string +// default: user@test.com +// responses: +// '200': +// description: 'Return all possible projects.' +// '400': +// description: 'Bad Request. Invalid user query param.' +// '500': +// description: 'Internal server error.' + +func GetProjects(c *gin.Context){ + controllers.Get(c,"mongo") +} + +// swagger:operation POST /projects FlutterApp CreateProjects +// Create a new project +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: body +// in: body +// description: 'Mandatory: name, dateRange, namespace, attributes, +// objects, permissions, authorLastUpdate, lastUpdate. +// Optional: showAvg, showSum, isPublic.' +// required: true +// format: object +// example: '{"attributes":["domain"],"authorLastUpdate":"helder","dateRange":"01/01/2023-02/02/2023", +// "lastUpdate":"02/02/2023","name":"test 1","namespace":"physical","objects":["siteB"],"showAvg":false, +// "showSum":false,"permissions":["user@test.com","admin"]}' +// responses: +// '200': +// description: 'Project successfully created.' +// '400': +// description: 'Bad Request. Invalid project format.' +// '500': +// description: 'Internal server error.' +func CreateProjects(c *gin.Context){ + controllers.Post(c,"mongo") +} +// swagger:operation PUT /projects/{ProjectID} FlutterApp UpdateProjects +// Replace the data of an existing project. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: ProjectID +// in: path +// description: 'ID of the project to update.' +// required: true +// type: string +// default: "1234" +// - name: body +// in: body +// description: 'Mandatory: name, dateRange, namespace, attributes, +// objects, permissions, authorLastUpdate, lastUpdate. +// Optional: showAvg, showSum, isPublic.' +// required: true +// format: object +// example: '{"attributes":["domain"],"authorLastUpdate":"helder","dateRange":"01/01/2023-02/02/2023", +// "lastUpdate":"02/02/2023","name":"test 1","namespace":"physical","objects":["siteB"],"showAvg":false, +// "showSum":false,"permissions":["user@test.com","admin"]}' +// responses: +// '200': +// description: Project successfully updated. +// '400': +// description: Bad Request. Invalid project format. +// '500': +// description: Internal server error +func UpdateProjects(c *gin.Context){ + controllers.Put(c,"mongo") +} + +// swagger:operation DELETE /projects/{ProjectID} FlutterApp DeleteProjects +// Delete an existing project. +// --- +// security: +// - Bearer: [] +// produces: +// - application/json +// parameters: +// - name: ProjectID +// in: path +// description: 'ID of the project to delete.' +// required: true +// type: string +// default: "1234" +// responses: +// '200': +// description: Project successfully updated. +// '404': +// description: Not Found. Invalid project ID. +// '500': +// description: Internal server error +func DeleteProjects(c *gin.Context){ + controllers.Delete(c,"mongo") +} \ No newline at end of file diff --git a/BFF/services/router.go b/BFF/services/router.go index d3650f0e1..3964941cb 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -63,6 +63,18 @@ func initOrganization(protected, unprotected *gin.RouterGroup){ protected.GET("/hierarchy/domains",handlers.GetCompleteDomainHierarchy) } +func initFlutterApp(protected, unprotected *gin.RouterGroup){ + protected.POST("/projects",handlers.CreateProjects) + protected.GET("/projects",handlers.GetProjects) + protected.DELETE("/projects/:id",handlers.DeleteProjects) + protected.PUT("/projects/:id",handlers.UpdateProjects) + +} +func initAbout(protected, unprotected *gin.RouterGroup){ + protected.GET("/stats",handlers.GetStats) + protected.POST("/versions",handlers.GetAPIVersion) +} + func initObjects(protected, unprotected *gin.RouterGroup){ protected.GET("/:entity",handlers.GetAllEntities) @@ -111,6 +123,7 @@ func InitRouter(apiList []models.API,env string ) *gin.Engine { initAuth(protected,unprotected) initOrganization(protected,unprotected) initObjects(protected,unprotected) + initAbout(protected,unprotected) //init healthcheck route diff --git a/BFF/swagger.yaml b/BFF/swagger.yaml index 13362a0a1..260bda12f 100644 --- a/BFF/swagger.yaml +++ b/BFF/swagger.yaml @@ -480,6 +480,19 @@ paths: - Bearer: [] tags: - Devices + /api/version: + get: + operationId: GetAPIVersion + produces: + - application/json + responses: + "200": + description: OK. A response body will be returned with version details. + security: + - Bearer: [] + summary: Gets the API version. + tags: + - About /domains/bulk: post: description: An array of domains should be provided in the body. @@ -614,6 +627,120 @@ paths: summary: Get an object from any entity. tags: - Objects + /projects: + get: + operationId: GetProjects + parameters: + - default: user@test.com + description: 'Email of the user whose projects are being requested. Example: /api/projects?user=user@test.com' + in: query + name: user + type: string + produces: + - application/json + responses: + "200": + description: Return all possible projects. + "400": + description: Bad Request. Invalid user query param. + "500": + description: Internal server error. + security: + - Bearer: [] + summary: Get a list of projects for the specified user. + tags: + - FlutterApp + post: + description: Create a new project + operationId: CreateProjects + parameters: + - description: 'Mandatory: name, dateRange, namespace, attributes, objects, permissions, authorLastUpdate, lastUpdate. Optional: showAvg, showSum, isPublic.' + example: '{"attributes":["domain"],"authorLastUpdate":"helder","dateRange":"01/01/2023-02/02/2023", "lastUpdate":"02/02/2023","name":"test 1","namespace":"physical","objects":["siteB"],"showAvg":false, "showSum":false,"permissions":["user@test.com","admin"]}' + format: object + in: body + name: body + required: true + produces: + - application/json + responses: + "200": + description: Project successfully created. + "400": + description: Bad Request. Invalid project format. + "500": + description: Internal server error. + security: + - Bearer: [] + tags: + - FlutterApp + /projects/{ProjectID}: + delete: + operationId: DeleteProjects + parameters: + - default: "1234" + description: ID of the project to delete. + in: path + name: ProjectID + required: true + type: string + produces: + - application/json + responses: + "200": + description: Project successfully updated. + "404": + description: Not Found. Invalid project ID. + "500": + description: Internal server error + security: + - Bearer: [] + summary: Delete an existing project. + tags: + - FlutterApp + put: + operationId: UpdateProjects + parameters: + - default: "1234" + description: ID of the project to update. + in: path + name: ProjectID + required: true + type: string + - description: 'Mandatory: name, dateRange, namespace, attributes, objects, permissions, authorLastUpdate, lastUpdate. Optional: showAvg, showSum, isPublic.' + example: '{"attributes":["domain"],"authorLastUpdate":"helder","dateRange":"01/01/2023-02/02/2023", "lastUpdate":"02/02/2023","name":"test 1","namespace":"physical","objects":["siteB"],"showAvg":false, "showSum":false,"permissions":["user@test.com","admin"]}' + format: object + in: body + name: body + required: true + produces: + - application/json + responses: + "200": + description: Project successfully updated. + "400": + description: Bad Request. Invalid project format. + "500": + description: Internal server error + security: + - Bearer: [] + summary: Replace the data of an existing project. + tags: + - FlutterApp + /stats: + get: + operationId: GetStats + produces: + - application/json + responses: + "200": + description: Request is valid. + "504": + description: Server error. + security: + - Bearer: [] + summary: Displays DB statistics. + tags: + - About /tempunits/{IdOrHierarchyName}: get: operationId: GetTempUnit From 2dc98d38b8c11f6bd362c58ee5c98e9a6d35f68d Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Tue, 8 Aug 2023 10:39:49 +0200 Subject: [PATCH 12/35] feat(bff): add bff to docker-compose --- BFF/Dockerfile | 28 ++++ BFF/controllers/sender.go | 5 +- BFF/go.mod | 50 ++++++ BFF/go.sum | 253 +++++++++++++++++++++++++++++++ BFF/services/router.go | 22 +-- deploy/docker/.env | 8 +- deploy/docker/docker-compose.yml | 23 ++- 7 files changed, 374 insertions(+), 15 deletions(-) create mode 100644 BFF/Dockerfile create mode 100644 BFF/go.sum diff --git a/BFF/Dockerfile b/BFF/Dockerfile new file mode 100644 index 000000000..189cb9191 --- /dev/null +++ b/BFF/Dockerfile @@ -0,0 +1,28 @@ +FROM golang:1.18.2-alpine3.16 AS build + +# Set the Current Working Directory inside the container +WORKDIR /build + +# We want to populate the module cache based on the go.{mod,sum} files. +COPY BFF/go.mod . +COPY BFF/go.sum . + +RUN go mod download + +COPY BFF . + + +# Build the Go app +RUN CGO_ENABLED=0 GOOS=linux go build -a -o ogree-bff -ldflags "-X main.version=${VERSION} -X 'main.build=$(date)'" . + +# Start fresh from a smaller image +FROM alpine:3.16 + +WORKDIR /bin + +COPY --from=build /build/ogree-bff . +COPY --from=build /build/swagger.yaml . + + +# Run the binary program produced by `go install` +CMD ["./ogree-bff"] \ No newline at end of file diff --git a/BFF/controllers/sender.go b/BFF/controllers/sender.go index e7ecf8df1..f7c160d07 100644 --- a/BFF/controllers/sender.go +++ b/BFF/controllers/sender.go @@ -39,7 +39,9 @@ func Send(method, URL, query ,key string, data interface{}) (*http.Response,erro if err != nil { return nil,err } - req.Header.Set("Authorization", "Bearer "+key) + if(key != ""){ + req.Header.Set("Authorization", "Bearer "+key) + } resp,err := client.Do(req) if err != nil { return nil,err @@ -95,6 +97,7 @@ func Post(c *gin.Context, api string){ c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) return } + key := token.ExtractToken(c) path := GetPath(c) resp,err := Send("POST",url+path,"",key,data) diff --git a/BFF/go.mod b/BFF/go.mod index 72e8ec78f..d1eeb79ad 100644 --- a/BFF/go.mod +++ b/BFF/go.mod @@ -1,3 +1,53 @@ module ogree-bff go 1.20 + +require ( + github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/gin-gonic/gin v1.9.1 + github.com/go-openapi/runtime v0.26.0 + github.com/gorilla/mux v1.8.0 + github.com/joho/godotenv v1.5.1 +) + +require ( + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/analysis v0.21.4 // indirect + github.com/go-openapi/errors v0.20.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/loads v0.21.2 // indirect + github.com/go-openapi/spec v0.20.8 // indirect + github.com/go-openapi/strfmt v0.21.7 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/validate v0.22.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/oklog/ulid v1.3.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + go.mongodb.org/mongo-driver v1.11.3 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/BFF/go.sum b/BFF/go.sum new file mode 100644 index 000000000..90d022503 --- /dev/null +++ b/BFF/go.sum @@ -0,0 +1,253 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +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/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= +github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= +github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= +github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= +github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= +github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= +github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= +github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= +github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= +github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= +github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= +github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= +github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.2/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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +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.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +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= +go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= +go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +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-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.5/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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.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-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/BFF/services/router.go b/BFF/services/router.go index 3964941cb..b29a6c8bc 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -66,8 +66,8 @@ func initOrganization(protected, unprotected *gin.RouterGroup){ func initFlutterApp(protected, unprotected *gin.RouterGroup){ protected.POST("/projects",handlers.CreateProjects) protected.GET("/projects",handlers.GetProjects) - protected.DELETE("/projects/:id",handlers.DeleteProjects) - protected.PUT("/projects/:id",handlers.UpdateProjects) + protected.DELETE("/projects/*id",handlers.DeleteProjects) + protected.PUT("/projects/*id",handlers.UpdateProjects) } func initAbout(protected, unprotected *gin.RouterGroup){ @@ -80,17 +80,17 @@ func initObjects(protected, unprotected *gin.RouterGroup){ protected.GET("/:entity",handlers.GetAllEntities) protected.POST("/:entity",handlers.CreateObject) - protected.GET("/objects/:hierarchyName",handlers.GetGenericObject) + protected.GET("/objects/*hierarchyName",handlers.GetGenericObject) - protected.GET("/:entity/:id",handlers.GetEntity) - protected.DELETE("/:entity/:id",handlers.DeleteObject) - protected.PATCH("/:entity/:id",handlers.PartialUpdateObject) - protected.PUT("/:entity/:id",handlers.UpdateObject) - protected.GET("/:entity/:id/all",handlers.GetEntityHierarchy) + protected.GET("/:entity/*id",handlers.GetEntity) + protected.DELETE("/:entity/*id",handlers.DeleteObject) + protected.PATCH("/:entity/*id",handlers.PartialUpdateObject) + protected.PUT("/:entity/*id",handlers.UpdateObject) + //protected.GET("/:entity/:id/all",handlers.GetEntityHierarchy) - protected.GET("/tempunits/:id",handlers.GetTempUnit) + protected.GET("/tempunits/*id",handlers.GetTempUnit) - protected.GET("/:entity/:id/:subent",handlers.GetEntitiesOfAncestor) + //protected.GET("/:entity/:id/:subent",handlers.GetEntitiesOfAncestor) protected.GET("/hierarchy",handlers.GetCompleteHierarchy) @@ -98,7 +98,7 @@ func initObjects(protected, unprotected *gin.RouterGroup){ //protected.GET("/:entity/:id/:HierarchalPath",handlers.GetEntitiesUsingNamesOfParents) - protected.POST("/validate/:entity",handlers.ValidateObject) + protected.POST("/validate/*entity",handlers.ValidateObject) } diff --git a/deploy/docker/.env b/deploy/docker/.env index bf80b7827..bc2a87261 100644 --- a/deploy/docker/.env +++ b/deploy/docker/.env @@ -19,5 +19,11 @@ ARANGO_DB=_system ARANGO_PORT=8529 ARANGO_API_USER=root ARANGO_API_PASSWORD=ogree -ARANGO_API_SECRET=myAwesomeApiSecret + +#BFF +BFF_BUILD_DIR=BFF +BFF_PORT=8085 + +#AUTH +AUTH_SECRET=myAwesomeApiSecret diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 1bee2f266..b18f99269 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -12,7 +12,7 @@ services: - db_user=${COMPOSE_PROJECT_NAME} - db_pass=${CUSTOMER_API_PASSWORD} - db=${COMPOSE_PROJECT_NAME} - - token_password=myAwesomeApiSecret + - token_password=${AUTH_SECRET} ports: - ${API_PORT}:3001 depends_on: @@ -80,7 +80,7 @@ services: restart: on-failure:10 - arrango_api: + arango_api: build: context: ${CORE_DIR} dockerfile: ${ARANGO_API_BUILD_DIR}/Dockerfile @@ -104,6 +104,25 @@ services: interval: 1m retries: 3 + ogree-bff: + build: + context: ${CORE_DIR} + dockerfile: ${BFF_BUILD_DIR}/Dockerfile + image: ogree-bff:${IMAGE_TAG} + restart: on-failure:10 + container_name: ${COMPOSE_PROJECT_NAME}_bff + environment: + - ENV=production + - ARANGO_API=http://${COMPOSE_PROJECT_NAME}_arango-api:${ARANGO_API_PORT} + - MONGO_API=http://${COMPOSE_PROJECT_NAME}_api:${API_PORT} + - BFF_PORT=${BFF_PORT} + - BFF_SECRET=${AUTH_SECRET} + depends_on: + - ogree_api + - arango_api + ports: + - ${BFF_PORT}:${BFF_PORT} + volumes: db: arangodb-persist: From d1777df145620781b5d3ca7ceb32dd9ab53a30f6 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Tue, 8 Aug 2023 10:46:31 +0200 Subject: [PATCH 13/35] fix(swagger): remove ussless swagger.yaml --- swagger.yaml | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 swagger.yaml diff --git a/swagger.yaml b/swagger.yaml deleted file mode 100644 index a26c975cb..000000000 --- a/swagger.yaml +++ /dev/null @@ -1,2 +0,0 @@ -paths: {} -swagger: "2.0" From 4f32bf193b4be95b9236be64430b647e1e32a325 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Tue, 8 Aug 2023 11:02:47 +0200 Subject: [PATCH 14/35] fix(bff): fix arango url in docker-compose --- deploy/docker/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index b18f99269..13aa89b1d 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -113,7 +113,7 @@ services: container_name: ${COMPOSE_PROJECT_NAME}_bff environment: - ENV=production - - ARANGO_API=http://${COMPOSE_PROJECT_NAME}_arango-api:${ARANGO_API_PORT} + - ARANGO_API=http://${COMPOSE_PROJECT_NAME}_arango_api:${ARANGO_API_PORT} - MONGO_API=http://${COMPOSE_PROJECT_NAME}_api:${API_PORT} - BFF_PORT=${BFF_PORT} - BFF_SECRET=${AUTH_SECRET} From b3c1966a1dbff9b095c61e4d420c96e32ad4c826 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Tue, 8 Aug 2023 16:06:31 +0200 Subject: [PATCH 15/35] fix(bff): many fix in bff - use json instead of yaml for swagger - add routes post/get connections and devices - use api-doc container for bff - change PostDevices statusCode from Found to BadRequest - Remove useless code of arango-api --- ARANGO_API/controllers/auth.go | 25 - ARANGO_API/database/devices.go | 2 +- ARANGO_API/dockerfile | 2 +- ARANGO_API/handlers/auth.go | 39 - ARANGO_API/handlers/database.go | 97 -- ARANGO_API/handlers/swagger.go | 4 +- ARANGO_API/models/auth.go | 29 - ARANGO_API/services/router.go | 4 - ARANGO_API/swagger.json | 541 ++++++++++ ARANGO_API/swagger.yaml | 499 --------- ARANGO_API/utils/token/token.go | 6 - BFF/Dockerfile | 2 +- BFF/controllers/sender.go | 23 +- BFF/handlers/about.go | 2 +- BFF/handlers/devices.go | 146 +++ BFF/handlers/swagger.go | 4 +- BFF/services/router.go | 6 + BFF/swagger.json | 1737 ++++++++++++++++++++++++++++++ BFF/swagger.yaml | 1021 ------------------ deploy/docker/.env | 2 - deploy/docker/docker-compose.yml | 6 +- 21 files changed, 2451 insertions(+), 1746 deletions(-) delete mode 100644 ARANGO_API/controllers/auth.go delete mode 100644 ARANGO_API/handlers/auth.go delete mode 100644 ARANGO_API/handlers/database.go delete mode 100644 ARANGO_API/models/auth.go create mode 100644 ARANGO_API/swagger.json delete mode 100644 ARANGO_API/swagger.yaml create mode 100644 BFF/swagger.json delete mode 100644 BFF/swagger.yaml diff --git a/ARANGO_API/controllers/auth.go b/ARANGO_API/controllers/auth.go deleted file mode 100644 index f884e23b3..000000000 --- a/ARANGO_API/controllers/auth.go +++ /dev/null @@ -1,25 +0,0 @@ -package controllers - -import ( - "arango-api/models" - "arango-api/utils/token" - "fmt" - "os" -) -func CheckLogin(user models.LoginInput) (string,error){ - var u models.User - u.Username = user.Username - u.Password = user.Password - apiUser := os.Getenv("API_USER") - apiPassword := os.Getenv("API_PASSWORD") - if apiUser == u.Username && apiPassword == u.Password{ - token,err := token.GenerateToken(1235) - if err != nil { - fmt.Println(err) - return "",err - } - return token,nil - } - return "", fmt.Errorf("Bad username or password"); - -} \ No newline at end of file diff --git a/ARANGO_API/database/devices.go b/ARANGO_API/database/devices.go index f2053c7aa..b9d2f6362 100644 --- a/ARANGO_API/database/devices.go +++ b/ARANGO_API/database/devices.go @@ -54,7 +54,7 @@ func InsertDevices(c *gin.Context, device map[string]string) ([]interface{}, *mo return nil, err } if existed { - return nil, &models.ErrorMessage{StatusCode: http.StatusFound, Message: "Device already existed"} + return nil, &models.ErrorMessage{StatusCode: http.StatusBadRequest, Message: "Device already existed"} } deviceStr, err := ParseToString(device) diff --git a/ARANGO_API/dockerfile b/ARANGO_API/dockerfile index b38fde977..0feaa3c05 100644 --- a/ARANGO_API/dockerfile +++ b/ARANGO_API/dockerfile @@ -21,7 +21,7 @@ FROM alpine:3.16 WORKDIR /bin COPY --from=build /build/arango-api . -COPY --from=build /build/swagger.yaml . +COPY --from=build /build/swagger.json . # Run the binary program produced by `go install` diff --git a/ARANGO_API/handlers/auth.go b/ARANGO_API/handlers/auth.go deleted file mode 100644 index 6fbe1db37..000000000 --- a/ARANGO_API/handlers/auth.go +++ /dev/null @@ -1,39 +0,0 @@ -package handlers - -import ( - "net/http" - "arango-api/models" - "arango-api/controllers" - "github.com/gin-gonic/gin" -) -// swagger:operation POST /login Login LoginToApi -// Login to api -// --- -// responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessLogin" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -func Login(c *gin.Context){ - var input models.LoginInput - - if err := c.BindJSON(&input); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - token, err := controllers.CheckLogin(input) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "username or password is incorrect."}) - return - } - - c.JSON(http.StatusOK, gin.H{"token":token}) - -} \ No newline at end of file diff --git a/ARANGO_API/handlers/database.go b/ARANGO_API/handlers/database.go deleted file mode 100644 index 0c0395546..000000000 --- a/ARANGO_API/handlers/database.go +++ /dev/null @@ -1,97 +0,0 @@ -package handlers - -import ( - "net/http" - - "arango-api/database" - "arango-api/models" - - "github.com/gin-gonic/gin" -) - -// swagger:operation GET /Database Database Database -// Get database name -// -// --- -// security: -// - Bearer: [] -// responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" - -func GetBDD(c *gin.Context) { - db, err := database.GetDBConn(c) - if err != nil { - c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) - return - } - addr, ok := c.Value("addr").(*string) - if !ok { - c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Fail to get database hostname"}) - return - } - - info, _ := (*db).Info(nil) - - c.IndentedJSON(http.StatusOK, gin.H{"message": "Connected to " + (*addr) + " on database: " + info.Name}) - -} - -// swagger:operation POST /Database Database ConnectBDD -// Connect to new bdd -// -// --- -// security: -// - Bearer: [] -// responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -func ConnectBDD(c *gin.Context) { - db, err := database.GetDBConn(c) - if err != nil && err.StatusCode != 404 { - c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) - return - } - - addr, ok := c.Value("addr").(*string) - if !ok { - c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Fail to get database hostname"}) - return - } - - var DBInfo models.DatabaseInfo - if err := c.BindJSON(&DBInfo); err != nil { - c.IndentedJSON(http.StatusBadRequest, gin.H{"message": err.Error()}) - return - } - - newDB, err := database.ConnectToArango(DBInfo.Host, DBInfo.Database, DBInfo.User, DBInfo.Password) - - if err != nil { - c.IndentedJSON(err.StatusCode, gin.H{"message": err.Message}) - return - } - - (*db) = newDB - (*addr) = DBInfo.Host - info, _ := (*db).Info(nil) - - c.IndentedJSON(http.StatusOK, gin.H{"message": "Connected to " + (*addr) + " on database: " + info.Name}) - -} diff --git a/ARANGO_API/handlers/swagger.go b/ARANGO_API/handlers/swagger.go index 9ef47db78..a146b12eb 100644 --- a/ARANGO_API/handlers/swagger.go +++ b/ARANGO_API/handlers/swagger.go @@ -9,8 +9,8 @@ import( func SwaggerHandler() *mux.Router{ pr := mux.NewRouter() - pr.Handle("/swagger.yaml", http.FileServer(http.Dir("./"))) - opts := middleware.SwaggerUIOpts{SpecURL: "swagger.yaml"} + pr.Handle("/swagger.json", http.FileServer(http.Dir("./"))) + opts := middleware.SwaggerUIOpts{SpecURL: "swagger.json"} sh := middleware.SwaggerUI(opts, nil) pr.Handle("/docs", sh) diff --git a/ARANGO_API/models/auth.go b/ARANGO_API/models/auth.go deleted file mode 100644 index b1395bb58..000000000 --- a/ARANGO_API/models/auth.go +++ /dev/null @@ -1,29 +0,0 @@ -package models - - -// swagger:model LoginInput -type LoginInput struct { - // username - // in: username - Username string `json:"username" binding:"required"` - // username - // in: password - Password string `json:"password" binding:"required"` -} - -type User struct { - ID uint `json:"id"` - Username string `json:"username" binding:"required"` - Password string `json:"password" binding:"required"` -} - -// swagger:model SuccessLogin -type SuccessLogin struct { - Token string `json:"token" binding:"required"` -} - -// swagger:parameters LoginToApi -type ReqLoginBody struct { - // in: body - Body LoginInput `json:"body"` -} diff --git a/ARANGO_API/services/router.go b/ARANGO_API/services/router.go index d80641978..5294349a4 100644 --- a/ARANGO_API/services/router.go +++ b/ARANGO_API/services/router.go @@ -50,10 +50,6 @@ func InitRouter(db driver.Database, addr string) *gin.Engine { proteted.POST("/Connections", handlers.PostConnection) proteted.DELETE("/Connections/:key", handlers.DeleteConnection) - proteted.GET("/Database", handlers.GetBDD) - proteted.POST("/Database", handlers.ConnectBDD) - - router.POST("/api/login",handlers.Login) router.GET("/api/health",func(c *gin.Context){ c.String(http.StatusAccepted,"") }) diff --git a/ARANGO_API/swagger.json b/ARANGO_API/swagger.json new file mode 100644 index 000000000..816cf9753 --- /dev/null +++ b/ARANGO_API/swagger.json @@ -0,0 +1,541 @@ +{ + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "schemes": [ + "http", + "https" + ], + "swagger": "2.0", + "info": { + "title": "Arrango API:", + "version": "1.0.0" + }, + "basePath": "/api", + "paths": { + "/Connections": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get Connection list", + "tags": [ + "Connections" + ], + "operationId": "Connection", + "parameters": [ + { + "type": "string", + "description": "Key of connection", + "name": "_key", + "in": "query" + }, + { + "type": "string", + "description": "From witch device", + "name": "_from", + "in": "query" + }, + { + "type": "string", + "description": "To witch device", + "name": "_to", + "in": "query" + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessConResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Create new Connection", + "tags": [ + "Connections" + ], + "operationId": "CreateConnection", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "schema": { + "$ref": "#/definitions/Connection" + } + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessConResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "/Connections/{connection}": { + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Delete Connection by key", + "tags": [ + "Connections" + ], + "operationId": "DeleteConnection", + "parameters": [ + { + "type": "string", + "description": "connection looking for", + "name": "connection", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "/Devices": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get Devices list", + "tags": [ + "Devices" + ], + "operationId": "Devices", + "parameters": [ + { + "type": "string", + "description": "Key of device", + "name": "_key", + "in": "query" + }, + { + "type": "string", + "description": "Name of device", + "name": "_name", + "in": "query" + }, + { + "type": "string", + "description": "Group_name of device", + "name": "group_name", + "in": "query" + }, + { + "type": "string", + "description": "Serial number of device", + "name": "serial", + "in": "query" + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Create new Devices", + "tags": [ + "Devices" + ], + "operationId": "CreateDevices", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "schema": { + "$ref": "#/definitions/Devices" + } + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "/Devices/ConnecteTo/{device}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get Devices connected to a device", + "tags": [ + "Devices" + ], + "operationId": "GetDevicesConnectedTo", + "parameters": [ + { + "type": "string", + "description": "Key of device", + "name": "device", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Filter devices by key", + "name": "_key", + "in": "query" + }, + { + "type": "string", + "description": "Name of device", + "name": "_name", + "in": "query" + }, + { + "type": "string", + "description": "Group_name of device", + "name": "group_name", + "in": "query" + }, + { + "type": "string", + "description": "Serial number of device", + "name": "serial", + "in": "query" + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "/Devices/{device}": { + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Delete Devices by key", + "tags": [ + "Devices" + ], + "operationId": "DeleteDevices", + "parameters": [ + { + "type": "string", + "description": "device looking for", + "name": "device", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + } + }, + "definitions": { + "Connection": { + "type": "object", + "properties": { + "_from": { + "description": "from Device\nin: _from", + "type": "string", + "x-go-name": "From", + "example": "devices/*" + }, + "_key": { + "description": "Primary key of device\nin: _key", + "type": "string", + "x-go-name": "Key", + "readOnly": true + }, + "_to": { + "description": "To device\nin: _to", + "type": "string", + "x-go-name": "To", + "example": "devices/*" + }, + "created": { + "description": "Date of connection's creation\nin: created", + "type": "string", + "x-go-name": "Created", + "example": "2016-04-22" + }, + "expired": { + "description": "Date of connection's expiration\nin: expired", + "type": "string", + "x-go-name": "Expired", + "example": "3000-01-01" + }, + "type": { + "description": "Type of connection\nin: type", + "type": "string", + "x-go-name": "Type", + "example": "parent of (between partens)" + } + }, + "x-go-package": "arango-api/models" + }, + "DatabaseInfo": { + "type": "object", + "properties": { + "database": { + "description": "Database name\nin: database", + "type": "string", + "x-go-name": "Database", + "example": "_system" + }, + "host": { + "description": "Host url of database\nin: host", + "type": "string", + "x-go-name": "Host", + "example": "http://localhost:8529" + }, + "password": { + "description": "Password of the user\nin: password", + "type": "string", + "x-go-name": "Password", + "example": "password" + }, + "user": { + "description": "User of database\nin: user", + "type": "string", + "x-go-name": "User", + "example": "root" + } + }, + "x-go-package": "arango-api/models" + }, + "Devices": { + "type": "object", + "properties": { + "_key": { + "description": "Primary key of device\nin: _key", + "type": "string", + "x-go-name": "Key", + "readOnly": true + }, + "_name": { + "description": "name of Devices\nin: _name", + "type": "string", + "x-go-name": "Name", + "example": "storage_bay" + }, + "category": { + "description": "category of Devices\nin: category", + "type": "string", + "x-go-name": "Category", + "example": "port" + }, + "created": { + "description": "Date of device's creation\nin: created", + "type": "string", + "x-go-name": "Created", + "example": "2016-04-22" + }, + "expired": { + "description": "Date of device's expiration\nin: expired", + "type": "string", + "x-go-name": "Expired", + "example": "3000-01-01" + }, + "group_name": { + "description": "group_name of Devices\nin: group_name", + "type": "string", + "x-go-name": "GroupName", + "example": "GS00OPSAN06" + }, + "hba_device_name": { + "description": "hba_device_name of Devices\nin: hba_device_name", + "type": "string", + "x-go-name": "HbaDeviceName", + "example": "nsa.*" + }, + "sp_name": { + "description": "sp_name of Devices\nin: sp_name", + "type": "string", + "x-go-name": "SpName", + "example": "sp_b" + }, + "sp_port_id": { + "description": "sp_port_id of Devices\nin: sp_port_id", + "type": "string", + "x-go-name": "SpPortId", + "example": "0" + }, + "storage_group_name": { + "description": "storage_group_name of Devices\nin: storage_group_name", + "type": "string", + "x-go-name": "StorageGroupName", + "example": "storage" + } + }, + "x-go-package": "arango-api/models" + }, + "ErrorResponse": { + "type": "object", + "properties": { + "message": { + "description": "Error Response Message\nin: message", + "type": "string", + "x-go-name": "Message" + } + }, + "x-go-package": "arango-api/models" + }, + "SuccessConResponse": { + "type": "object", + "properties": { + "Connections": { + "description": "Success\nin : array", + "type": "array", + "items": { + "$ref": "#/definitions/Connection" + } + } + }, + "x-go-package": "arango-api/models" + }, + "SuccessResponse": { + "type": "object", + "properties": { + "Devices": { + "description": "Success\nin : array", + "type": "array", + "items": { + "$ref": "#/definitions/Devices" + } + } + }, + "x-go-package": "arango-api/models" + } + }, + "securityDefinitions": { + "Bearer": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +} \ No newline at end of file diff --git a/ARANGO_API/swagger.yaml b/ARANGO_API/swagger.yaml deleted file mode 100644 index d0ad9b95a..000000000 --- a/ARANGO_API/swagger.yaml +++ /dev/null @@ -1,499 +0,0 @@ -basePath: /api -consumes: - - application/json -definitions: - Connection: - properties: - _from: - description: |- - from Device - in: _from - example: devices/* - type: string - x-go-name: From - _key: - description: |- - Primary key of device - in: _key - readOnly: true - type: string - x-go-name: Key - _to: - description: |- - To device - in: _to - example: devices/* - type: string - x-go-name: To - created: - description: |- - Date of connection's creation - in: created - example: "2016-04-22" - type: string - x-go-name: Created - expired: - description: |- - Date of connection's expiration - in: expired - example: "3000-01-01" - type: string - x-go-name: Expired - type: - description: |- - Type of connection - in: type - example: parent of (between partens) - type: string - x-go-name: Type - type: object - x-go-package: arango-api/models - DatabaseInfo: - properties: - database: - description: |- - Database name - in: database - example: _system - type: string - x-go-name: Database - host: - description: |- - Host url of database - in: host - example: http://localhost:8529 - type: string - x-go-name: Host - password: - description: |- - Password of the user - in: password - example: password - type: string - x-go-name: Password - user: - description: |- - User of database - in: user - example: root - type: string - x-go-name: User - type: object - x-go-package: arango-api/models - Devices: - properties: - _key: - description: |- - Primary key of device - in: _key - readOnly: true - type: string - x-go-name: Key - _name: - description: |- - name of Devices - in: _name - example: storage_bay - type: string - x-go-name: Name - category: - description: |- - category of Devices - in: category - example: port - type: string - x-go-name: Category - created: - description: |- - Date of device's creation - in: created - example: "2016-04-22" - type: string - x-go-name: Created - expired: - description: |- - Date of device's expiration - in: expired - example: "3000-01-01" - type: string - x-go-name: Expired - group_name: - description: |- - group_name of Devices - in: group_name - example: GS00OPSAN06 - type: string - x-go-name: GroupName - hba_device_name: - description: |- - hba_device_name of Devices - in: hba_device_name - example: nsa.* - type: string - x-go-name: HbaDeviceName - sp_name: - description: |- - sp_name of Devices - in: sp_name - example: sp_b - type: string - x-go-name: SpName - sp_port_id: - description: |- - sp_port_id of Devices - in: sp_port_id - example: "0" - type: string - x-go-name: SpPortId - storage_group_name: - description: |- - storage_group_name of Devices - in: storage_group_name - example: storage - type: string - x-go-name: StorageGroupName - type: object - x-go-package: arango-api/models - ErrorResponse: - properties: - message: - description: |- - Error Response Message - in: message - type: string - x-go-name: Message - type: object - x-go-package: arango-api/models - LoginInput: - properties: - password: - description: |- - username - in: password - type: string - x-go-name: Password - username: - description: |- - username - in: username - type: string - x-go-name: Username - type: object - x-go-package: arango-api/models - SuccessConResponse: - properties: - Connections: - description: |- - Success - in : array - items: - $ref: '#/definitions/Connection' - type: array - type: object - x-go-package: arango-api/models - SuccessLogin: - properties: - token: - type: string - x-go-name: Token - type: object - x-go-package: arango-api/models - SuccessResponse: - properties: - Devices: - description: |- - Success - in : array - items: - $ref: '#/definitions/Devices' - type: array - type: object - x-go-package: arango-api/models -info: - title: 'Arrango API:' - version: 1.0.0 -paths: - /Connections: - get: - description: Get Connection list - operationId: Connection - parameters: - - description: Key of connection - in: query - name: _key - type: string - - description: From witch device - in: query - name: _from - type: string - - description: To witch device - in: query - name: _to - type: string - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/SuccessConResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Connections - post: - description: Create new Connection - operationId: CreateConnection - parameters: - - in: body - name: body - schema: - $ref: '#/definitions/Connection' - x-go-name: Body - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/SuccessConResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Connections - /Connections/{connection}: - delete: - description: Delete Connection by key - operationId: DeleteConnection - parameters: - - description: connection looking for - in: path - name: connection - required: true - type: string - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/SuccessResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Connections - /Database: - get: - description: Get database name - operationId: Database - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/ErrorResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Database - post: - description: Connect to new bdd - operationId: ConnectBDD - parameters: - - in: body - name: body - schema: - $ref: '#/definitions/DatabaseInfo' - x-go-name: Body - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/ErrorResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Database - /Devices: - get: - description: Get Devices list - operationId: Devices - parameters: - - description: Key of device - in: query - name: _key - type: string - - description: Name of device - in: query - name: _name - type: string - - description: Group_name of device - in: query - name: group_name - type: string - - description: Serial number of device - in: query - name: serial - type: string - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/SuccessResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Devices - post: - description: Create new Devices - operationId: CreateDevices - parameters: - - in: body - name: body - schema: - $ref: '#/definitions/Devices' - x-go-name: Body - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/SuccessResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Devices - /Devices/{device}: - delete: - description: Delete Devices by key - operationId: DeleteDevices - parameters: - - description: device looking for - in: path - name: device - required: true - type: string - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/SuccessResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Devices - /Devices/ConnecteTo/{device}: - get: - description: Get Devices connected to a device - operationId: GetDevicesConnectedTo - parameters: - - description: Key of device - in: path - name: device - required: true - type: string - - description: Filter devices by key - in: query - name: _key - type: string - - description: Name of device - in: query - name: _name - type: string - - description: Group_name of device - in: query - name: group_name - type: string - - description: Serial number of device - in: query - name: serial - type: string - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/SuccessResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Devices - /login: - post: - description: Login to api - operationId: LoginToApi - parameters: - - in: body - name: body - schema: - $ref: '#/definitions/LoginInput' - x-go-name: Body - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/SuccessLogin' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - tags: - - Login -produces: - - application/json -schemes: - - http - - https -securityDefinitions: - Bearer: - in: header - name: Authorization - type: apiKey -swagger: "2.0" diff --git a/ARANGO_API/utils/token/token.go b/ARANGO_API/utils/token/token.go index 7ef3d4253..eff595103 100644 --- a/ARANGO_API/utils/token/token.go +++ b/ARANGO_API/utils/token/token.go @@ -12,13 +12,7 @@ import ( ) func GenerateToken(user_id uint) (string, error) { - /* - token_lifespan,err := strconv.Atoi(os.Getenv("TOKEN_HOUR_LIFESPAN")) - if err != nil { - return "",err - } - */ token_lifespan := 24 claims := jwt.MapClaims{} claims["authorized"] = true diff --git a/BFF/Dockerfile b/BFF/Dockerfile index 189cb9191..cabc13407 100644 --- a/BFF/Dockerfile +++ b/BFF/Dockerfile @@ -21,7 +21,7 @@ FROM alpine:3.16 WORKDIR /bin COPY --from=build /build/ogree-bff . -COPY --from=build /build/swagger.yaml . +COPY --from=build /build/swagger.json . # Run the binary program produced by `go install` diff --git a/BFF/controllers/sender.go b/BFF/controllers/sender.go index f7c160d07..19480e3d8 100644 --- a/BFF/controllers/sender.go +++ b/BFF/controllers/sender.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "io" "net/http" "ogree-bff/models" @@ -42,12 +41,8 @@ func Send(method, URL, query ,key string, data interface{}) (*http.Response,erro if(key != ""){ req.Header.Set("Authorization", "Bearer "+key) } - resp,err := client.Do(req) - if err != nil { - return nil,err - } - return resp, nil + return client.Do(req) } func GetJSONBody(resp *http.Response) models.Message { @@ -58,7 +53,6 @@ func GetJSONBody(resp *http.Response) models.Message { if err != nil { return models.Message{StatusCode: http.StatusInternalServerError,Message: err.Error()} } - fmt.Println(string(body)) err = json.Unmarshal(body, &responseBody) if err != nil { return models.Message{StatusCode: http.StatusInternalServerError,Message: err.Error()} @@ -76,7 +70,7 @@ func Get(c *gin.Context, api string){ query := GetQueryString(c) path := GetPath(c) resp,err := Send("GET",url+path,query,key,nil) - if err != nil { + if err != nil && resp == nil{ c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) return } @@ -101,8 +95,10 @@ func Post(c *gin.Context, api string){ key := token.ExtractToken(c) path := GetPath(c) resp,err := Send("POST",url+path,"",key,data) - if err != nil { + fmt.Println(err) + if err != nil && resp == nil{ c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return } result := GetJSONBody(resp) c.IndentedJSON(resp.StatusCode, result.Message) @@ -117,8 +113,9 @@ func Delete(c *gin.Context, api string){ key := token.ExtractToken(c) path := GetPath(c) resp,err := Send("DELETE",url+path,"",key,nil) - if err != nil { + if err != nil && resp == nil{ c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return } result := GetJSONBody(resp) c.IndentedJSON(resp.StatusCode, result.Message) @@ -139,8 +136,9 @@ func Patch(c *gin.Context, api string){ key := token.ExtractToken(c) path := GetPath(c) resp,err := Send("PATCH",url+path,"",key,data) - if err != nil { + if err != nil && resp == nil{ c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return } result := GetJSONBody(resp) c.IndentedJSON(resp.StatusCode, result.Message) @@ -161,8 +159,9 @@ func Put(c *gin.Context, api string){ key := token.ExtractToken(c) path := GetPath(c) resp,err := Send("PUT",url+path,"",key,data) - if err != nil { + if err != nil && resp == nil{ c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return } result := GetJSONBody(resp) c.IndentedJSON(resp.StatusCode, result.Message) diff --git a/BFF/handlers/about.go b/BFF/handlers/about.go index 3ec2b2c24..acb68ba38 100644 --- a/BFF/handlers/about.go +++ b/BFF/handlers/about.go @@ -22,7 +22,7 @@ func GetStats(c *gin.Context){ controllers.Get(c,"mongo") } -// swagger:operation GET /api/version About GetAPIVersion +// swagger:operation GET /version About GetAPIVersion // Gets the API version. // --- // security: diff --git a/BFF/handlers/devices.go b/BFF/handlers/devices.go index 8a81b05e4..1503c62c8 100644 --- a/BFF/handlers/devices.go +++ b/BFF/handlers/devices.go @@ -94,4 +94,150 @@ func GetDevices(c *gin.Context) { // "$ref": "#/definitions/ErrorResponse" func GetDevicesConnectedTo(c *gin.Context) { controllers.Get(c,"arango") +} +// swagger:operation POST /Devices Devices CreateDevices +// Create new Devices +// +// --- +// security: +// - Bearer: [] +// parameters: +// - name: body +// in: body +// description: 'Mandatory: _name, group_name,created.' +// required: true +// format: object +// example: '{"_name": "server", "group_name": "exwipen22","created": "2022-07-18"}' +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func CreateDevices(c *gin.Context) { + controllers.Post(c,"arango") +} + +// swagger:operation DELETE /Devices/{device} Devices DeleteDevices +// Delete Devices by key +// +// --- +// parameters: +// - name: device +// in: path +// description: device looking for +// required: true +// type: string +// security: +// - Bearer: [] +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func DeleteDevice(c *gin.Context){ + controllers.Delete(c,"arango") +} + +// swagger:operation GET /Connections Devices GetConnections +// Get Connection list +// +// --- +// parameters: +// - name: _key +// in: query +// description: Key of connection +// required: false +// type: string +// - name: _from +// in: query +// description: From witch device +// required: false +// type: string +// - name: _to +// in: query +// description: To witch device +// required: false +// type: string +// security: +// - Bearer: [] +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func GetConnections(c *gin.Context){ + controllers.Get(c,"arango") +} +// swagger:operation POST /Connections Devices CreateConnection +// Create new Connection +// +// --- +// security: +// - Bearer: [] +// parameters: +// - name: body +// in: body +// description: 'Mandatory: _from, _to.' +// required: true +// format: object +// example: '{"_from": "devices/123", "_to": "devices/111"}' +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func CreateConnections(c *gin.Context){ + controllers.Post(c,"arango") +} + +// swagger:operation DELETE /Connections/{connection} Devices DeleteConnection +// Delete Connection by key +// +// --- +// security: +// - Bearer: [] +// parameters: +// - name: connection +// in: path +// description: connection looking for +// required: true +// type: string +// +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func DeleteConnections(c *gin.Context){ + controllers.Delete(c,"arango") } \ No newline at end of file diff --git a/BFF/handlers/swagger.go b/BFF/handlers/swagger.go index 9ef47db78..a146b12eb 100644 --- a/BFF/handlers/swagger.go +++ b/BFF/handlers/swagger.go @@ -9,8 +9,8 @@ import( func SwaggerHandler() *mux.Router{ pr := mux.NewRouter() - pr.Handle("/swagger.yaml", http.FileServer(http.Dir("./"))) - opts := middleware.SwaggerUIOpts{SpecURL: "swagger.yaml"} + pr.Handle("/swagger.json", http.FileServer(http.Dir("./"))) + opts := middleware.SwaggerUIOpts{SpecURL: "swagger.json"} sh := middleware.SwaggerUI(opts, nil) pr.Handle("/docs", sh) diff --git a/BFF/services/router.go b/BFF/services/router.go index b29a6c8bc..35f0364b1 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -41,6 +41,12 @@ func initDevices(protected, unprotected *gin.RouterGroup){ protected.GET("/Devices",handlers.GetDevices) protected.GET("/Devices/ConnecteTo/:key",handlers.GetDevicesConnectedTo) + protected.POST("/Devices",handlers.CreateDevices) + protected.DELETE("/Devices/:id",handlers.DeleteDevice) + + protected.GET("/Connections",handlers.GetConnections) + protected.POST("/Connections",handlers.CreateConnections) + protected.DELETE("/Connections/:id",handlers.DeleteConnections) } func initAuth(protected, unprotected *gin.RouterGroup){ diff --git a/BFF/swagger.json b/BFF/swagger.json new file mode 100644 index 000000000..9fd40d01f --- /dev/null +++ b/BFF/swagger.json @@ -0,0 +1,1737 @@ +{ + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "schemes": [ + "http", + "https" + ], + "swagger": "2.0", + "info": { + "title": "Ogree BFF:", + "version": "1.0.0" + }, + "basePath": "/api", + "paths": { + "/Connections": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get Connection list", + "tags": [ + "Devices" + ], + "operationId": "GetConnections", + "parameters": [ + { + "type": "string", + "description": "Key of connection", + "name": "_key", + "in": "query" + }, + { + "type": "string", + "description": "From witch device", + "name": "_from", + "in": "query" + }, + { + "type": "string", + "description": "To witch device", + "name": "_to", + "in": "query" + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Create new Connection", + "tags": [ + "Devices" + ], + "operationId": "CreateConnection", + "parameters": [ + { + "format": "object", + "example": "{\"_from\": \"devices/123\", \"_to\": \"devices/111\"}", + "description": "Mandatory: _from, _to.", + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "/Connections/{connection}": { + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Delete Connection by key", + "tags": [ + "Devices" + ], + "operationId": "DeleteConnection", + "parameters": [ + { + "type": "string", + "description": "connection looking for", + "name": "connection", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "/Devices": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get Devices list", + "tags": [ + "Devices" + ], + "operationId": "Devices", + "parameters": [ + { + "type": "string", + "description": "Key of device", + "name": "_key", + "in": "query" + }, + { + "type": "string", + "description": "Name of device", + "name": "_name", + "in": "query" + }, + { + "type": "string", + "description": "Group_name of device", + "name": "group_name", + "in": "query" + }, + { + "type": "string", + "description": "Serial number of device", + "name": "serial", + "in": "query" + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Create new Devices", + "tags": [ + "Devices" + ], + "operationId": "CreateDevices", + "parameters": [ + { + "format": "object", + "example": "{\"_name\": \"server\", \"group_name\": \"exwipen22\",\"created\": \"2022-07-18\"}", + "description": "Mandatory: _name, group_name,created.", + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "/Devices/ConnecteTo/{device}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get Devices connected to a device", + "tags": [ + "Devices" + ], + "operationId": "GetDevicesConnectedTo", + "parameters": [ + { + "type": "string", + "description": "Key of device", + "name": "device", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Filter devices by key", + "name": "_key", + "in": "query" + }, + { + "type": "string", + "description": "Name of device", + "name": "_name", + "in": "query" + }, + { + "type": "string", + "description": "Group_name of device", + "name": "group_name", + "in": "query" + }, + { + "type": "string", + "description": "Serial number of device", + "name": "serial", + "in": "query" + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "/Devices/{device}": { + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Delete Devices by key", + "tags": [ + "Devices" + ], + "operationId": "DeleteDevices", + "parameters": [ + { + "type": "string", + "description": "device looking for", + "name": "device", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "/domains/bulk": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "An array of domains should be provided in the body.", + "produces": [ + "application/json" + ], + "tags": [ + "Organization" + ], + "summary": "Create multiple domains in a single request.", + "operationId": "CreateBulkDomain", + "parameters": [ + { + "default": [ + {} + ], + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "Request processed. Check the response body for individual results for each of the sent domains" + }, + "400": { + "description": "Bad format: body is not a valid list of domains." + } + } + } + }, + "/hierarchy": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Return is arranged by relationship (father:[children])\nand category (category:[objects]), starting with \"Root\":[sites].\nUser permissions apply.", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Returns system complete hierarchy.", + "operationId": "GetCompleteHierarchy", + "responses": { + "200": { + "description": "Request is valid." + }, + "500": { + "description": "Server error." + } + } + } + }, + "/hierarchy/attributes": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Return is arranged by hierarchyName (objHierarchyName:{attributes}).\nUser permissions apply.", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Returns attributes of all objects.", + "operationId": "GetCompleteHierarchyAttrs", + "responses": { + "200": { + "description": "Request is valid." + }, + "500": { + "description": "Server error." + } + } + } + }, + "/hierarchy/domains": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Return is arranged by relationship (father:[children]),\nstarting with \"Root\":[root domains].", + "produces": [ + "application/json" + ], + "tags": [ + "Organization" + ], + "summary": "Returns domain complete hierarchy.", + "operationId": "GetCompleteDomainHierarchy", + "responses": { + "200": { + "description": "Request is valid." + }, + "500": { + "description": "Server error." + } + } + } + }, + "/login": { + "post": { + "description": "Create a new JWT Key. This can also be used to verify credentials\nThe authorize and 'Try it out' buttons don't work", + "produces": [ + "application/json" + ], + "tags": [ + "Authentication" + ], + "summary": "Generates a new JWT Key for the client.", + "operationId": "Authenticate", + "parameters": [ + { + "format": "object", + "example": "{\"email\": \"user@test.com\", \"password\": \"secret123\"}", + "description": "Mandatory: email and password.", + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "Authenticated" + }, + "400": { + "description": "Bad request" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/objects/{hierarchyName}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Gets an object from any of the physical entities with no need to specify it.\nThe hierarchyName must be provided in the URL as a parameter.", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Get an object from any entity.", + "operationId": "GetGenericObject", + "parameters": [ + { + "description": "hierarchyName of the object", + "name": "hierarchyName", + "in": "path", + "required": true + }, + { + "description": "specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored.", + "name": "fieldOnly", + "in": "query" + }, + { + "description": "filter objects by lastUpdated \u003e= startDate. Format: yyyy-mm-dd", + "name": "startDate", + "in": "query" + }, + { + "description": "filter objects by lastUpdated \u003c= endDate. Format: yyyy-mm-dd", + "name": "endDate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Found. A response body will be returned with a meaningful message." + }, + "404": { + "description": "Not Found. An error message will be returned." + } + } + } + }, + "/projects": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "FlutterApp" + ], + "summary": "Get a list of projects for the specified user.", + "operationId": "GetProjects", + "parameters": [ + { + "type": "string", + "default": "user@test.com", + "description": "Email of the user whose projects are being requested. Example: /api/projects?user=user@test.com", + "name": "user", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Return all possible projects." + }, + "400": { + "description": "Bad Request. Invalid user query param." + }, + "500": { + "description": "Internal server error." + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Create a new project", + "produces": [ + "application/json" + ], + "tags": [ + "FlutterApp" + ], + "operationId": "CreateProjects", + "parameters": [ + { + "format": "object", + "example": "{\"attributes\":[\"domain\"],\"authorLastUpdate\":\"helder\",\"dateRange\":\"01/01/2023-02/02/2023\", \"lastUpdate\":\"02/02/2023\",\"name\":\"test 1\",\"namespace\":\"physical\",\"objects\":[\"siteB\"],\"showAvg\":false, \"showSum\":false,\"permissions\":[\"user@test.com\",\"admin\"]}", + "description": "Mandatory: name, dateRange, namespace, attributes, objects, permissions, authorLastUpdate, lastUpdate. Optional: showAvg, showSum, isPublic.", + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "Project successfully created." + }, + "400": { + "description": "Bad Request. Invalid project format." + }, + "500": { + "description": "Internal server error." + } + } + } + }, + "/projects/{ProjectID}": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "FlutterApp" + ], + "summary": "Replace the data of an existing project.", + "operationId": "UpdateProjects", + "parameters": [ + { + "type": "string", + "default": "1234", + "description": "ID of the project to update.", + "name": "ProjectID", + "in": "path", + "required": true + }, + { + "format": "object", + "example": "{\"attributes\":[\"domain\"],\"authorLastUpdate\":\"helder\",\"dateRange\":\"01/01/2023-02/02/2023\", \"lastUpdate\":\"02/02/2023\",\"name\":\"test 1\",\"namespace\":\"physical\",\"objects\":[\"siteB\"],\"showAvg\":false, \"showSum\":false,\"permissions\":[\"user@test.com\",\"admin\"]}", + "description": "Mandatory: name, dateRange, namespace, attributes, objects, permissions, authorLastUpdate, lastUpdate. Optional: showAvg, showSum, isPublic.", + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "Project successfully updated." + }, + "400": { + "description": "Bad Request. Invalid project format." + }, + "500": { + "description": "Internal server error" + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "FlutterApp" + ], + "summary": "Delete an existing project.", + "operationId": "DeleteProjects", + "parameters": [ + { + "type": "string", + "default": "1234", + "description": "ID of the project to delete.", + "name": "ProjectID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Project successfully updated." + }, + "404": { + "description": "Not Found. Invalid project ID." + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/stats": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "About" + ], + "summary": "Displays DB statistics.", + "operationId": "GetStats", + "responses": { + "200": { + "description": "Request is valid." + }, + "504": { + "description": "Server error." + } + } + } + }, + "/tempunits/{IdOrHierarchyName}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Gets the temperatureUnit attribute of the parent site of given object.", + "operationId": "GetTempUnit", + "parameters": [ + { + "type": "string", + "default": "siteA", + "description": "ID or hierarchy name of desired object. For templates the slug is the ID.", + "name": "IdOrHierarchyName", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Found. A response body will be returned with a meaningful message." + }, + "404": { + "description": "Nothing Found. An error message will be returned." + } + } + } + }, + "/token/valid": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authentication" + ], + "summary": "Verify if token sent in the header is valid.", + "operationId": "VerifyToken", + "responses": { + "200": { + "description": "Token is valid." + }, + "403": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/users": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Organization" + ], + "summary": "Get a list of users that the caller is allowed to see.", + "operationId": "GetAllAccounts", + "responses": { + "200": { + "description": "Return all possible users" + }, + "500": { + "description": "Internal server error" + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Create an account with email and password credentials, it returns\na JWT key to use with the API.", + "produces": [ + "application/json" + ], + "tags": [ + "Organization" + ], + "summary": "Create a new user user.", + "operationId": "CreateAccount", + "parameters": [ + { + "format": "object", + "example": "{\"name\": \"John Doe\", \"roles\": {\"*\": \"manager\"}, \"email\": \"user@test.com\", \"password\": \"secret123\"}", + "description": "Mandatory: email, password and roles. Optional: name. Roles is an object with domains as keys and roles as values. Possible roles: manager, user and viewer", + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "201": { + "description": "New account created" + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "User not authorised to create an account" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/users/bulk": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Organization" + ], + "summary": "Create multiples users with one request.", + "operationId": "CreateBulk", + "parameters": [ + { + "format": "object", + "example": "[{\"name\": \"John Doe\", \"roles\": {\"*\": \"manager\"}, \"email\": \"user@test.com\"}]", + "description": "An array of users. Same mandatory and optional parameters as user apply, except for password. If not provided, one will be automatically created by the API.", + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "Request processed, check response body for results" + }, + "400": { + "description": "Bad request" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/users/password/change": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authentication" + ], + "summary": "For logged in user to change its own password.", + "operationId": "ModifyUserPassword", + "parameters": [ + { + "type": "json", + "example": "{\"currentPassword\": \"myOldPassword\", \"newPassword\": \"myNewPassword\"}", + "description": "Mandatory: currentPassword and newPassword.", + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "Password changed" + }, + "400": { + "description": "Bad request" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/users/password/forgot": { + "post": { + "description": "Public endpoint to request a reset of a user's password (forgot my password).\nIf the email is valid, an email with a reset token/link will be sent to the user.", + "produces": [ + "application/json" + ], + "tags": [ + "Authentication" + ], + "summary": "Forgot my password.", + "operationId": "UserForgotPassword", + "parameters": [ + { + "type": "string", + "example": "{\"email\": \"user@test.com\"}", + "description": "Mandatory: email.", + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "request processed. If account exists, an email with a reset token is sent" + }, + "400": { + "description": "Bad request" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/users/password/reset": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "For user that first called forgot enpoint to change its password.\nA reset token generated by the forgot endpoint should be provided as the Authentication header.", + "produces": [ + "application/json" + ], + "tags": [ + "Authentication" + ], + "summary": "Reset password after forgot.", + "operationId": "ResetUserPassword", + "parameters": [ + { + "type": "json", + "example": "{\"newPassword\": \"myNewPassword\"}", + "description": "Mandatory: currentPassword and newPassword.", + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "Password changed" + }, + "400": { + "description": "Bad request" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/users/{userid}": { + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Organization" + ], + "summary": "Remove the specified user account.", + "operationId": "RemoveAccount", + "parameters": [ + { + "type": "string", + "example": "someUserId", + "description": "The ID of the user to delete", + "name": "userid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "User removed" + }, + "400": { + "description": "User ID not valid or not found" + }, + "403": { + "description": "Caller not authorised to delete this user" + }, + "500": { + "description": "Internal server error" + } + } + }, + "patch": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Organization" + ], + "summary": "Modify user permissions: domain and role.", + "operationId": "ModifyUserRoles", + "parameters": [ + { + "type": "string", + "example": "someUserId", + "description": "The ID of the user to modify roles", + "name": "userid", + "in": "path", + "required": true + }, + { + "type": "json", + "example": "{\"roles\": {\"*\": \"manager\"}}", + "description": "An object with domains as keys and roles as values", + "name": "roles", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "User roles modified" + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "Caller not authorised to modify this user" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/validate/{entity}": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Checks the received data and verifies if the object can be created in the system.", + "operationId": "ValidateObject", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.", + "name": "entity", + "in": "path", + "required": true + }, + { + "default": {}, + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "200": { + "description": "Createable. A response body will be returned with a meaningful message." + }, + "400": { + "description": "Bad request. A response body with an error message will be returned." + }, + "404": { + "description": "Not Found. An error message will be returned." + } + } + } + }, + "/version": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "About" + ], + "summary": "Gets the API version.", + "operationId": "GetAPIVersion", + "responses": { + "200": { + "description": "OK. A response body will be returned with version details." + } + } + } + }, + "/{entity}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Returns JSON body with all specified objects of type.", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Gets all present objects for specified entity (category).", + "operationId": "GetAllEntities", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices", + "name": "entity", + "in": "path", + "required": true + }, + { + "description": "specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored.", + "name": "fieldOnly", + "in": "query" + }, + { + "description": "filter objects by lastUpdated \u003e= startDate. Format: yyyy-mm-dd", + "name": "startDate", + "in": "query" + }, + { + "description": "filter objects by lastUpdated \u003c= endDate. Format: yyyy-mm-dd", + "name": "endDate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Found. A response body will be returned with a meaningful message." + }, + "404": { + "description": "Nothing Found. An error message will be returned." + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Creates an object of the given entity in the system.", + "operationId": "CreateObject", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.", + "name": "entity", + "in": "path", + "required": true + }, + { + "default": {}, + "name": "body", + "in": "body", + "required": true + } + ], + "responses": { + "201": { + "description": "Created. A response body will be returned with a meaningful message." + }, + "400": { + "description": "Bad request. A response body with an error message will be returned." + } + } + } + }, + "/{entity}/{IdOrHierarchyName}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "The ID or hierarchy name must be provided in the URL parameter.", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Gets an Object of the given entity.", + "operationId": "GetEntity", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.", + "name": "entity", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "siteA", + "description": "ID or hierarchy name of desired object. For templates the slug is the ID.", + "name": "IdOrHierarchyName", + "in": "path", + "required": true + }, + { + "description": "specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored.", + "name": "fieldOnly", + "in": "query" + }, + { + "description": "filter objects by lastUpdated \u003e= startDate. Format: yyyy-mm-dd", + "name": "startDate", + "in": "query" + }, + { + "description": "filter objects by lastUpdated \u003c= endDate. Format: yyyy-mm-dd", + "name": "endDate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Found. A response body will be returned with a meaningful message." + }, + "400": { + "description": "Bad request. An error message will be returned." + }, + "404": { + "description": "Not Found. An error message will be returned." + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Deletes an Object in the system.", + "operationId": "DeleteObject", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.", + "name": "entity", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "siteA", + "description": "ID or hierarchy name of desired object. For templates the slug is the ID.", + "name": "IdOrHierarchyName", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Successfully deleted object. No response body will be returned" + }, + "404": { + "description": "Not found. An error message will be returned" + } + } + }, + "patch": { + "security": [ + { + "Bearer": [] + } + ], + "description": "This is the preferred method for modifying data in the system.\nIf you want to do a full data replace, please use PUT instead.\nIf no data is effectively changed, an OK will still be returned.", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Partially update object.", + "operationId": "PartialUpdateObject", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.", + "name": "entity", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "siteA", + "description": "ID or hierarchy name of desired object. For templates the slug is the ID.", + "name": "IdOrHierarchyName", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Updated. A response body will be returned with a meaningful message." + }, + "400": { + "description": "Bad request. An error message will be returned." + }, + "404": { + "description": "Not Found. An error message will be returned." + } + } + } + }, + "/{entity}/{IdOrHierarchyName}/all": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Returns JSON body with all subobjects under the Object.", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Get object and all its children.", + "operationId": "GetEntityHierarchy", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.", + "name": "entity", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "siteA", + "description": "ID or hierarchy name of desired object. For templates the slug is the ID.", + "name": "IdOrHierarchyName", + "in": "path", + "required": true + }, + { + "type": "string", + "default": 1, + "description": "Limits the level of hierarchy for retrieval. if not specified for devices then the default value is maximum. Example: /api/devices/{id}/all?limit=2", + "name": "limit", + "in": "query" + }, + { + "description": "specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored.", + "name": "fieldOnly", + "in": "query" + }, + { + "description": "filter objects by lastUpdated \u003e= startDate. Format: yyyy-mm-dd", + "name": "startDate", + "in": "query" + }, + { + "description": "filter objects by lastUpdated \u003c= endDate. Format: yyyy-mm-dd", + "name": "endDate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Found. A response body will be returned with a meaningful message." + }, + "404": { + "description": "Nothing Found. An error message will be returned." + } + } + } + }, + "/{entity}/{id}/{subent}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "For Example: /api/sites/{id}/buildings\nWill return all buildings of a site\nReturns JSON body with all subobjects under the Object", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Obtain all objects 2 levels lower in the system.", + "operationId": "GetEntitiesOfAncestor", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Indicates the entity. Only values of \"sites\", \"buildings\", \"rooms\" are acceptable", + "name": "entity", + "in": "query", + "required": true + }, + { + "type": "int", + "default": 999, + "description": "ID of object", + "name": "ID", + "in": "query", + "required": true + }, + { + "type": "string", + "default": "buildings", + "description": "Objects which 2 are levels lower in the hierarchy.", + "name": "subent", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "Found. A response body will be returned with a meaningful message." + }, + "404": { + "description": "Nothing Found. An error message will be returned." + } + } + } + }, + "/{entity}?": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Gets an Object using any attribute (with the exception of description)\nvia query in the system\nThe attributes are in the form {attr}=xyz\u0026{attr1}=abc\nAnd any combination can be used given that at least 1 is provided.", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Gets an object filtering by attribute.", + "operationId": "GetEntityByQuery", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.", + "name": "entity", + "in": "path", + "required": true + }, + { + "description": "specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored.", + "name": "fieldOnly", + "in": "query" + }, + { + "description": "filter objects by lastUpdated \u003e= startDate. Format: yyyy-mm-dd", + "name": "startDate", + "in": "query" + }, + { + "description": "filter objects by lastUpdated \u003c= endDate. Format: yyyy-mm-dd", + "name": "endDate", + "in": "query" + }, + { + "type": "string", + "default": "domain=DemoDomain", + "example": "vendor=ibm ; name=siteA ; orientation=front", + "description": "Any other object attributes can be queried. Replace attributes here by the name of the attribute followed by its value.", + "name": "attributes", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Found. A response body will be returned with a meaningful message." + }, + "404": { + "description": "Not found. An error message will be returned." + } + } + } + }, + "/{firstEntity}/{id}/{HierarchalPath}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "The path should begin with an entity name (firstEntity) and the ID of an object of this entity\nfollowed by a hierarchal path until the desired objet, that is,\na sequence of entity names (category) and object names.", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Get an object with its full hierarchal path.", + "operationId": "GetEntitiesUsingNamesOfParents", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Root entity followed by an id. Can be: sites, buildings, rooms, racks or devices", + "name": "firstEntity", + "in": "query", + "required": true + }, + { + "type": "string", + "default": "123", + "description": "id of object of firstEntity", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "/buildings/BuildingB/rooms/RoomA", + "example": "/api/sites/{id}/buildings/{building_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/acs/{ac_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/corridors/{corridor_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/panels/{panel_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/groups/{group_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/racks/{rack_name}/devices/{device_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/racks/{rack_name} ; /api/buildings/{id}/rooms/{room_name} ; /api/buildings/{id}/rooms/{room_name}/acs/{ac_name} ; /api/buildings/{id}/rooms/{room_name}/corridors/{corridor_name} ; /api/buildings/{id}/rooms/{room_name}/panels/{panel_name} ; /api/buildings/{id}/rooms/{room_name}/groups/{group_name} ; /api/buildings/{id}/rooms/{room_name}/rack/{rack_name} ; /api/buildings/{id}/rooms/{room_name}/racks/{rack_name}/devices/{device_name} ; /api/rooms/{id}/acs/{ac_name} ; /api/rooms/{id}/corridors/{corridor_name} ; /api/rooms/{id}/panels/{panel_name} ; /api/rooms/{id}/groups/{group_name} ; /api/rooms/{id}/racks/{rack_name}/devices/{device_name} ; /api/racks/{id}/devices/{device_name} ; /api/devices/{id}/devices/{device_name} ;", + "description": "Hierarchal path to desired object.", + "name": "HierarchalPath", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Found. A response body will be returned with a meaningful message." + }, + "404": { + "description": "Not Found. An error message will be returned." + } + } + } + }, + "/{objs}/{IdOrHierarchyName}": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "This method will replace the existing data with the JSON\nreceived, thus fully replacing the data. If you do not\nwant to do this, please use PATCH.\nIf no data is effectively changed, an OK will still be returned.", + "produces": [ + "application/json" + ], + "tags": [ + "Objects" + ], + "summary": "Completely update object.", + "operationId": "UpdateObject", + "parameters": [ + { + "type": "string", + "default": "sites", + "description": "Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.", + "name": "entity", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "siteA", + "description": "ID or hierarchy name of desired object. For templates the slug is the ID.", + "name": "IdOrHierarchyName", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Updated. A response body will be returned with a meaningful message." + }, + "400": { + "description": "Bad request. An error message will be returned." + }, + "404": { + "description": "Not Found. An error message will be returned." + } + } + } + } + }, + "definitions": { + "ErrorResponse": { + "type": "object", + "properties": { + "message": { + "description": "Error Response Message\nin: message", + "type": "string", + "x-go-name": "Message" + } + }, + "x-go-package": "ogree-bff/models" + }, + "LoginInput": { + "type": "object", + "properties": { + "email": { + "description": "email\nin: email", + "type": "string", + "x-go-name": "Email" + }, + "password": { + "description": "username\nin: password", + "type": "string", + "x-go-name": "Password" + } + }, + "x-go-package": "ogree-bff/models" + }, + "SuccessLogin": { + "type": "object", + "properties": { + "token": { + "type": "string", + "x-go-name": "Token" + } + }, + "x-go-package": "ogree-bff/models" + }, + "SuccessResponse": { + "type": "object", + "properties": { + "message": { + "description": "Error Response Message\nin: message", + "type": "string", + "x-go-name": "Message" + } + }, + "x-go-package": "ogree-bff/models" + } + }, + "securityDefinitions": { + "Bearer": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +} \ No newline at end of file diff --git a/BFF/swagger.yaml b/BFF/swagger.yaml deleted file mode 100644 index 260bda12f..000000000 --- a/BFF/swagger.yaml +++ /dev/null @@ -1,1021 +0,0 @@ -basePath: /api -consumes: - - application/json -definitions: - ErrorResponse: - properties: - message: - description: |- - Error Response Message - in: message - type: string - x-go-name: Message - type: object - x-go-package: ogree-bff/models - LoginInput: - properties: - email: - description: |- - email - in: email - type: string - x-go-name: Email - password: - description: |- - username - in: password - type: string - x-go-name: Password - type: object - x-go-package: ogree-bff/models - SuccessLogin: - properties: - token: - type: string - x-go-name: Token - type: object - x-go-package: ogree-bff/models - SuccessResponse: - properties: - message: - description: |- - Error Response Message - in: message - type: string - x-go-name: Message - type: object - x-go-package: ogree-bff/models -info: - title: 'Ogree BFF:' - version: 1.0.0 -paths: - /{entity}: - get: - description: Returns JSON body with all specified objects of type. - operationId: GetAllEntities - parameters: - - default: sites - description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices' - in: path - name: entity - required: true - type: string - - description: specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored. - in: query - name: fieldOnly - - description: 'filter objects by lastUpdated >= startDate. Format: yyyy-mm-dd' - in: query - name: startDate - - description: 'filter objects by lastUpdated <= endDate. Format: yyyy-mm-dd' - in: query - name: endDate - produces: - - application/json - responses: - "200": - description: Found. A response body will be returned with a meaningful message. - "404": - description: Nothing Found. An error message will be returned. - security: - - Bearer: [] - summary: Gets all present objects for specified entity (category). - tags: - - Objects - post: - operationId: CreateObject - parameters: - - default: sites - description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' - in: path - name: entity - required: true - type: string - - default: {} - in: body - name: body - required: true - produces: - - application/json - responses: - "201": - description: Created. A response body will be returned with a meaningful message. - "400": - description: Bad request. A response body with an error message will be returned. - security: - - Bearer: [] - summary: Creates an object of the given entity in the system. - tags: - - Objects - /{entity}/{IdOrHierarchyName}: - delete: - operationId: DeleteObject - parameters: - - default: sites - description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' - in: path - name: entity - required: true - type: string - - default: siteA - description: ID or hierarchy name of desired object. For templates the slug is the ID. - in: path - name: IdOrHierarchyName - required: true - type: string - produces: - - application/json - responses: - "204": - description: Successfully deleted object. No response body will be returned - "404": - description: Not found. An error message will be returned - security: - - Bearer: [] - summary: Deletes an Object in the system. - tags: - - Objects - get: - description: The ID or hierarchy name must be provided in the URL parameter. - operationId: GetEntity - parameters: - - default: sites - description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' - in: path - name: entity - required: true - type: string - - default: siteA - description: ID or hierarchy name of desired object. For templates the slug is the ID. - in: path - name: IdOrHierarchyName - required: true - type: string - - description: specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored. - in: query - name: fieldOnly - - description: 'filter objects by lastUpdated >= startDate. Format: yyyy-mm-dd' - in: query - name: startDate - - description: 'filter objects by lastUpdated <= endDate. Format: yyyy-mm-dd' - in: query - name: endDate - produces: - - application/json - responses: - "200": - description: Found. A response body will be returned with a meaningful message. - "400": - description: Bad request. An error message will be returned. - "404": - description: Not Found. An error message will be returned. - security: - - Bearer: [] - summary: Gets an Object of the given entity. - tags: - - Objects - patch: - description: |- - This is the preferred method for modifying data in the system. - If you want to do a full data replace, please use PUT instead. - If no data is effectively changed, an OK will still be returned. - operationId: PartialUpdateObject - parameters: - - default: sites - description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' - in: path - name: entity - required: true - type: string - - default: siteA - description: ID or hierarchy name of desired object. For templates the slug is the ID. - in: path - name: IdOrHierarchyName - required: true - type: string - produces: - - application/json - responses: - "200": - description: Updated. A response body will be returned with a meaningful message. - "400": - description: Bad request. An error message will be returned. - "404": - description: Not Found. An error message will be returned. - security: - - Bearer: [] - summary: Partially update object. - tags: - - Objects - /{entity}/{IdOrHierarchyName}/all: - get: - description: Returns JSON body with all subobjects under the Object. - operationId: GetEntityHierarchy - parameters: - - default: sites - description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' - in: path - name: entity - required: true - type: string - - default: siteA - description: ID or hierarchy name of desired object. For templates the slug is the ID. - in: path - name: IdOrHierarchyName - required: true - type: string - - default: 1 - description: 'Limits the level of hierarchy for retrieval. if not specified for devices then the default value is maximum. Example: /api/devices/{id}/all?limit=2' - in: query - name: limit - type: string - - description: specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored. - in: query - name: fieldOnly - - description: 'filter objects by lastUpdated >= startDate. Format: yyyy-mm-dd' - in: query - name: startDate - - description: 'filter objects by lastUpdated <= endDate. Format: yyyy-mm-dd' - in: query - name: endDate - produces: - - application/json - responses: - "200": - description: Found. A response body will be returned with a meaningful message. - "404": - description: Nothing Found. An error message will be returned. - security: - - Bearer: [] - summary: Get object and all its children. - tags: - - Objects - /{entity}/{id}/{subent}: - get: - description: |- - For Example: /api/sites/{id}/buildings - Will return all buildings of a site - Returns JSON body with all subobjects under the Object - operationId: GetEntitiesOfAncestor - parameters: - - default: sites - description: Indicates the entity. Only values of "sites", "buildings", "rooms" are acceptable - in: query - name: entity - required: true - type: string - - default: 999 - description: ID of object - in: query - name: ID - required: true - type: int - - default: buildings - description: Objects which 2 are levels lower in the hierarchy. - in: query - name: subent - required: true - type: string - produces: - - application/json - responses: - "200": - description: Found. A response body will be returned with a meaningful message. - "404": - description: Nothing Found. An error message will be returned. - security: - - Bearer: [] - summary: Obtain all objects 2 levels lower in the system. - tags: - - Objects - /{entity}?: - get: - description: |- - Gets an Object using any attribute (with the exception of description) - via query in the system - The attributes are in the form {attr}=xyz&{attr1}=abc - And any combination can be used given that at least 1 is provided. - operationId: GetEntityByQuery - parameters: - - default: sites - description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' - in: path - name: entity - required: true - type: string - - description: specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored. - in: query - name: fieldOnly - - description: 'filter objects by lastUpdated >= startDate. Format: yyyy-mm-dd' - in: query - name: startDate - - description: 'filter objects by lastUpdated <= endDate. Format: yyyy-mm-dd' - in: query - name: endDate - - default: domain=DemoDomain - description: Any other object attributes can be queried. Replace attributes here by the name of the attribute followed by its value. - example: vendor=ibm ; name=siteA ; orientation=front - in: query - name: attributes - type: string - produces: - - application/json - responses: - "204": - description: Found. A response body will be returned with a meaningful message. - "404": - description: Not found. An error message will be returned. - security: - - Bearer: [] - summary: Gets an object filtering by attribute. - tags: - - Objects - /{firstEntity}/{id}/{HierarchalPath}: - get: - description: |- - The path should begin with an entity name (firstEntity) and the ID of an object of this entity - followed by a hierarchal path until the desired objet, that is, - a sequence of entity names (category) and object names. - operationId: GetEntitiesUsingNamesOfParents - parameters: - - default: sites - description: 'Root entity followed by an id. Can be: sites, buildings, rooms, racks or devices' - in: query - name: firstEntity - required: true - type: string - - default: "123" - description: id of object of firstEntity - in: path - name: id - required: true - type: string - - default: /buildings/BuildingB/rooms/RoomA - description: Hierarchal path to desired object. - example: /api/sites/{id}/buildings/{building_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/acs/{ac_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/corridors/{corridor_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/panels/{panel_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/groups/{group_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/racks/{rack_name}/devices/{device_name} ; /api/sites/{id}/buildings/{building_name}/rooms/{room_name}/racks/{rack_name} ; /api/buildings/{id}/rooms/{room_name} ; /api/buildings/{id}/rooms/{room_name}/acs/{ac_name} ; /api/buildings/{id}/rooms/{room_name}/corridors/{corridor_name} ; /api/buildings/{id}/rooms/{room_name}/panels/{panel_name} ; /api/buildings/{id}/rooms/{room_name}/groups/{group_name} ; /api/buildings/{id}/rooms/{room_name}/rack/{rack_name} ; /api/buildings/{id}/rooms/{room_name}/racks/{rack_name}/devices/{device_name} ; /api/rooms/{id}/acs/{ac_name} ; /api/rooms/{id}/corridors/{corridor_name} ; /api/rooms/{id}/panels/{panel_name} ; /api/rooms/{id}/groups/{group_name} ; /api/rooms/{id}/racks/{rack_name}/devices/{device_name} ; /api/racks/{id}/devices/{device_name} ; /api/devices/{id}/devices/{device_name} ; - in: path - name: HierarchalPath - required: true - type: string - produces: - - application/json - responses: - "200": - description: Found. A response body will be returned with a meaningful message. - "404": - description: Not Found. An error message will be returned. - security: - - Bearer: [] - summary: Get an object with its full hierarchal path. - tags: - - Objects - /{objs}/{IdOrHierarchyName}: - put: - description: |- - This method will replace the existing data with the JSON - received, thus fully replacing the data. If you do not - want to do this, please use PATCH. - If no data is effectively changed, an OK will still be returned. - operationId: UpdateObject - parameters: - - default: sites - description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' - in: path - name: entity - required: true - type: string - - default: siteA - description: ID or hierarchy name of desired object. For templates the slug is the ID. - in: path - name: IdOrHierarchyName - required: true - type: string - produces: - - application/json - responses: - "200": - description: Updated. A response body will be returned with a meaningful message. - "400": - description: Bad request. An error message will be returned. - "404": - description: Not Found. An error message will be returned. - security: - - Bearer: [] - summary: Completely update object. - tags: - - Objects - /Devices: - get: - description: Get Devices list - operationId: Devices - parameters: - - description: Key of device - in: query - name: _key - type: string - - description: Name of device - in: query - name: _name - type: string - - description: Group_name of device - in: query - name: group_name - type: string - - description: Serial number of device - in: query - name: serial - type: string - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/SuccessResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Devices - /Devices/ConnecteTo/{device}: - get: - description: Get Devices connected to a device - operationId: GetDevicesConnectedTo - parameters: - - description: Key of device - in: path - name: device - required: true - type: string - - description: Filter devices by key - in: query - name: _key - type: string - - description: Name of device - in: query - name: _name - type: string - - description: Group_name of device - in: query - name: group_name - type: string - - description: Serial number of device - in: query - name: serial - type: string - responses: - "200": - description: successful - schema: - items: - $ref: '#/definitions/SuccessResponse' - "500": - description: Error - schema: - items: - $ref: '#/definitions/ErrorResponse' - security: - - Bearer: [] - tags: - - Devices - /api/version: - get: - operationId: GetAPIVersion - produces: - - application/json - responses: - "200": - description: OK. A response body will be returned with version details. - security: - - Bearer: [] - summary: Gets the API version. - tags: - - About - /domains/bulk: - post: - description: An array of domains should be provided in the body. - operationId: CreateBulkDomain - parameters: - - default: - - {} - in: body - name: body - required: true - produces: - - application/json - responses: - "200": - description: Request processed. Check the response body for individual results for each of the sent domains - "400": - description: 'Bad format: body is not a valid list of domains.' - security: - - Bearer: [] - summary: Create multiple domains in a single request. - tags: - - Organization - /hierarchy: - get: - description: |- - Return is arranged by relationship (father:[children]) - and category (category:[objects]), starting with "Root":[sites]. - User permissions apply. - operationId: GetCompleteHierarchy - produces: - - application/json - responses: - "200": - description: Request is valid. - "500": - description: Server error. - security: - - Bearer: [] - summary: Returns system complete hierarchy. - tags: - - Objects - /hierarchy/attributes: - get: - description: |- - Return is arranged by hierarchyName (objHierarchyName:{attributes}). - User permissions apply. - operationId: GetCompleteHierarchyAttrs - produces: - - application/json - responses: - "200": - description: Request is valid. - "500": - description: Server error. - security: - - Bearer: [] - summary: Returns attributes of all objects. - tags: - - Objects - /hierarchy/domains: - get: - description: |- - Return is arranged by relationship (father:[children]), - starting with "Root":[root domains]. - operationId: GetCompleteDomainHierarchy - produces: - - application/json - responses: - "200": - description: Request is valid. - "500": - description: Server error. - security: - - Bearer: [] - summary: Returns domain complete hierarchy. - tags: - - Organization - /login: - post: - description: |- - Create a new JWT Key. This can also be used to verify credentials - The authorize and 'Try it out' buttons don't work - operationId: Authenticate - parameters: - - description: 'Mandatory: email and password.' - example: '{"email": "user@test.com", "password": "secret123"}' - format: object - in: body - name: body - required: true - produces: - - application/json - responses: - "200": - description: Authenticated - "400": - description: Bad request - "500": - description: Internal server error - summary: Generates a new JWT Key for the client. - tags: - - Authentication - /objects/{hierarchyName}: - get: - description: |- - Gets an object from any of the physical entities with no need to specify it. - The hierarchyName must be provided in the URL as a parameter. - operationId: GetGenericObject - parameters: - - description: hierarchyName of the object - in: path - name: hierarchyName - required: true - - description: specify which object field to show in response. Multiple fieldOnly can be added. An invalid field is simply ignored. - in: query - name: fieldOnly - - description: 'filter objects by lastUpdated >= startDate. Format: yyyy-mm-dd' - in: query - name: startDate - - description: 'filter objects by lastUpdated <= endDate. Format: yyyy-mm-dd' - in: query - name: endDate - produces: - - application/json - responses: - "200": - description: Found. A response body will be returned with a meaningful message. - "404": - description: Not Found. An error message will be returned. - security: - - Bearer: [] - summary: Get an object from any entity. - tags: - - Objects - /projects: - get: - operationId: GetProjects - parameters: - - default: user@test.com - description: 'Email of the user whose projects are being requested. Example: /api/projects?user=user@test.com' - in: query - name: user - type: string - produces: - - application/json - responses: - "200": - description: Return all possible projects. - "400": - description: Bad Request. Invalid user query param. - "500": - description: Internal server error. - security: - - Bearer: [] - summary: Get a list of projects for the specified user. - tags: - - FlutterApp - post: - description: Create a new project - operationId: CreateProjects - parameters: - - description: 'Mandatory: name, dateRange, namespace, attributes, objects, permissions, authorLastUpdate, lastUpdate. Optional: showAvg, showSum, isPublic.' - example: '{"attributes":["domain"],"authorLastUpdate":"helder","dateRange":"01/01/2023-02/02/2023", "lastUpdate":"02/02/2023","name":"test 1","namespace":"physical","objects":["siteB"],"showAvg":false, "showSum":false,"permissions":["user@test.com","admin"]}' - format: object - in: body - name: body - required: true - produces: - - application/json - responses: - "200": - description: Project successfully created. - "400": - description: Bad Request. Invalid project format. - "500": - description: Internal server error. - security: - - Bearer: [] - tags: - - FlutterApp - /projects/{ProjectID}: - delete: - operationId: DeleteProjects - parameters: - - default: "1234" - description: ID of the project to delete. - in: path - name: ProjectID - required: true - type: string - produces: - - application/json - responses: - "200": - description: Project successfully updated. - "404": - description: Not Found. Invalid project ID. - "500": - description: Internal server error - security: - - Bearer: [] - summary: Delete an existing project. - tags: - - FlutterApp - put: - operationId: UpdateProjects - parameters: - - default: "1234" - description: ID of the project to update. - in: path - name: ProjectID - required: true - type: string - - description: 'Mandatory: name, dateRange, namespace, attributes, objects, permissions, authorLastUpdate, lastUpdate. Optional: showAvg, showSum, isPublic.' - example: '{"attributes":["domain"],"authorLastUpdate":"helder","dateRange":"01/01/2023-02/02/2023", "lastUpdate":"02/02/2023","name":"test 1","namespace":"physical","objects":["siteB"],"showAvg":false, "showSum":false,"permissions":["user@test.com","admin"]}' - format: object - in: body - name: body - required: true - produces: - - application/json - responses: - "200": - description: Project successfully updated. - "400": - description: Bad Request. Invalid project format. - "500": - description: Internal server error - security: - - Bearer: [] - summary: Replace the data of an existing project. - tags: - - FlutterApp - /stats: - get: - operationId: GetStats - produces: - - application/json - responses: - "200": - description: Request is valid. - "504": - description: Server error. - security: - - Bearer: [] - summary: Displays DB statistics. - tags: - - About - /tempunits/{IdOrHierarchyName}: - get: - operationId: GetTempUnit - parameters: - - default: siteA - description: ID or hierarchy name of desired object. For templates the slug is the ID. - in: path - name: IdOrHierarchyName - required: true - type: string - produces: - - application/json - responses: - "200": - description: Found. A response body will be returned with a meaningful message. - "404": - description: Nothing Found. An error message will be returned. - security: - - Bearer: [] - summary: Gets the temperatureUnit attribute of the parent site of given object. - tags: - - Objects - /token/valid: - get: - operationId: VerifyToken - produces: - - application/json - responses: - "200": - description: Token is valid. - "403": - description: Unauthorized - "500": - description: Internal server error - security: - - Bearer: [] - summary: Verify if token sent in the header is valid. - tags: - - Authentication - /users: - get: - operationId: GetAllAccounts - produces: - - application/json - responses: - "200": - description: Return all possible users - "500": - description: Internal server error - security: - - Bearer: [] - summary: Get a list of users that the caller is allowed to see. - tags: - - Organization - post: - description: |- - Create an account with email and password credentials, it returns - a JWT key to use with the API. - operationId: CreateAccount - parameters: - - description: 'Mandatory: email, password and roles. Optional: name. Roles is an object with domains as keys and roles as values. Possible roles: manager, user and viewer' - example: '{"name": "John Doe", "roles": {"*": "manager"}, "email": "user@test.com", "password": "secret123"}' - format: object - in: body - name: body - required: true - produces: - - application/json - responses: - "201": - description: New account created - "400": - description: Bad request - "403": - description: User not authorised to create an account - "500": - description: Internal server error - security: - - Bearer: [] - summary: Create a new user user. - tags: - - Organization - /users/{userid}: - delete: - operationId: RemoveAccount - parameters: - - description: The ID of the user to delete - example: someUserId - in: path - name: userid - required: true - type: string - produces: - - application/json - responses: - "200": - description: User removed - "400": - description: User ID not valid or not found - "403": - description: Caller not authorised to delete this user - "500": - description: Internal server error - security: - - Bearer: [] - summary: Remove the specified user account. - tags: - - Organization - patch: - operationId: ModifyUserRoles - parameters: - - description: The ID of the user to modify roles - example: someUserId - in: path - name: userid - required: true - type: string - - description: An object with domains as keys and roles as values - example: '{"roles": {"*": "manager"}}' - in: body - name: roles - required: true - type: json - produces: - - application/json - responses: - "200": - description: User roles modified - "400": - description: Bad request - "403": - description: Caller not authorised to modify this user - "500": - description: Internal server error - security: - - Bearer: [] - summary: 'Modify user permissions: domain and role.' - tags: - - Organization - /users/bulk: - post: - operationId: CreateBulk - parameters: - - description: An array of users. Same mandatory and optional parameters as user apply, except for password. If not provided, one will be automatically created by the API. - example: '[{"name": "John Doe", "roles": {"*": "manager"}, "email": "user@test.com"}]' - format: object - in: body - name: body - required: true - produces: - - application/json - responses: - "200": - description: Request processed, check response body for results - "400": - description: Bad request - "500": - description: Internal server error - security: - - Bearer: [] - summary: Create multiples users with one request. - tags: - - Organization - /users/password/change: - post: - operationId: ModifyUserPassword - parameters: - - description: 'Mandatory: currentPassword and newPassword.' - example: '{"currentPassword": "myOldPassword", "newPassword": "myNewPassword"}' - in: body - name: body - required: true - type: json - produces: - - application/json - responses: - "200": - description: Password changed - "400": - description: Bad request - "500": - description: Internal server error - security: - - Bearer: [] - summary: For logged in user to change its own password. - tags: - - Authentication - /users/password/forgot: - post: - description: |- - Public endpoint to request a reset of a user's password (forgot my password). - If the email is valid, an email with a reset token/link will be sent to the user. - operationId: UserForgotPassword - parameters: - - description: 'Mandatory: email.' - example: '{"email": "user@test.com"}' - in: body - name: body - required: true - type: string - produces: - - application/json - responses: - "200": - description: request processed. If account exists, an email with a reset token is sent - "400": - description: Bad request - "500": - description: Internal server error - summary: Forgot my password. - tags: - - Authentication - /users/password/reset: - post: - description: |- - For user that first called forgot enpoint to change its password. - A reset token generated by the forgot endpoint should be provided as the Authentication header. - operationId: ResetUserPassword - parameters: - - description: 'Mandatory: currentPassword and newPassword.' - example: '{"newPassword": "myNewPassword"}' - in: body - name: body - required: true - type: json - produces: - - application/json - responses: - "200": - description: Password changed - "400": - description: Bad request - "500": - description: Internal server error - security: - - Bearer: [] - summary: Reset password after forgot. - tags: - - Authentication - /validate/{entity}: - post: - operationId: ValidateObject - parameters: - - default: sites - description: 'Entity (same as category) of the object. Accepted values: sites, domains, buildings, rooms, racks, devices, acs, panels, cabinets, groups, corridors, room-templates, obj-templates, bldg-templates, stray-devices.' - in: path - name: entity - required: true - type: string - - default: {} - in: body - name: body - required: true - produces: - - application/json - responses: - "200": - description: Createable. A response body will be returned with a meaningful message. - "400": - description: Bad request. A response body with an error message will be returned. - "404": - description: Not Found. An error message will be returned. - security: - - Bearer: [] - summary: Checks the received data and verifies if the object can be created in the system. - tags: - - Objects -produces: - - application/json -schemes: - - http - - https -securityDefinitions: - Bearer: - in: header - name: Authorization - type: apiKey -swagger: "2.0" diff --git a/deploy/docker/.env b/deploy/docker/.env index bc2a87261..74cb5cf88 100644 --- a/deploy/docker/.env +++ b/deploy/docker/.env @@ -17,8 +17,6 @@ ARANGO_PASS=password ARANGO_USER=root ARANGO_DB=_system ARANGO_PORT=8529 -ARANGO_API_USER=root -ARANGO_API_PASSWORD=ogree #BFF BFF_BUILD_DIR=BFF diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 13aa89b1d..c5b83ed7b 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -47,7 +47,7 @@ services: ports: - ${API_DOC_UI_PORT}:8080 environment: - SWAGGER_JSON_URL: https://raw.githubusercontent.com/ditrit/OGrEE-Core/${IMAGE_TAG}/API/swagger.json + SWAGGER_JSON_URL: https://raw.githubusercontent.com/ditrit/OGrEE-Core/${IMAGE_TAG}/BFF/swagger.json restart: on-failure:10 depends_on: - ogree_api @@ -93,9 +93,7 @@ services: - ARANGO_DATABASE=${ARANGO_DB} - ARANGO_USER=${ARANGO_USER} - ARANGO_PASSWORD=${ARANGO_PASS} - - API_USER=${ARANGO_API_USER} - - API_PASSWORD=${ARANGO_API_PASSWORD} - - API_SECRET=${ARANGO_API_SECRET} + - API_SECRET=${AUTH_SECRET} ports: - ${ARANGO_API_PORT}:8080 healthcheck: From b720dc58f67c5b272a7b153272d3b0fc44efb8c8 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Wed, 9 Aug 2023 10:01:48 +0200 Subject: [PATCH 16/35] fix(bff): return text message if response body is not json --- BFF/controllers/sender.go | 4 ++-- BFF/services/router.go | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/BFF/controllers/sender.go b/BFF/controllers/sender.go index 19480e3d8..183573e5a 100644 --- a/BFF/controllers/sender.go +++ b/BFF/controllers/sender.go @@ -55,9 +55,9 @@ func GetJSONBody(resp *http.Response) models.Message { } err = json.Unmarshal(body, &responseBody) if err != nil { - return models.Message{StatusCode: http.StatusInternalServerError,Message: err.Error()} + return models.Message{StatusCode: resp.StatusCode,Message: gin.H{"message":string(body)}} } - return models.Message{StatusCode: http.StatusAccepted,Message: responseBody} + return models.Message{StatusCode: resp.StatusCode,Message: responseBody} } func Get(c *gin.Context, api string){ diff --git a/BFF/services/router.go b/BFF/services/router.go index 35f0364b1..f8d01a3ad 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -92,7 +92,6 @@ func initObjects(protected, unprotected *gin.RouterGroup){ protected.DELETE("/:entity/*id",handlers.DeleteObject) protected.PATCH("/:entity/*id",handlers.PartialUpdateObject) protected.PUT("/:entity/*id",handlers.UpdateObject) - //protected.GET("/:entity/:id/all",handlers.GetEntityHierarchy) protected.GET("/tempunits/*id",handlers.GetTempUnit) From bf2bf3db9999188374c10752f660c39b29e61913 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Wed, 9 Aug 2023 14:18:15 +0200 Subject: [PATCH 17/35] feat(bff): modify commandline get into CLI to use arango --- CLI/ast.go | 30 ++++++++++++++++ CLI/controllers/commandController.go | 52 +++++++++++++++++++++++++++- CLI/parser.go | 9 ++++- 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/CLI/ast.go b/CLI/ast.go index 5939d8a44..4578a5dfb 100644 --- a/CLI/ast.go +++ b/CLI/ast.go @@ -368,6 +368,36 @@ func (n *getObjectNode) execute() (interface{}, error) { return obj, nil } +type getPNode struct { + path node + filter node +} + +func (n *getPNode) execute() (interface{}, error) { + val, err := n.path.execute() + if err != nil { + return nil, err + } + path, ok := val.(string) + if !ok { + return nil, fmt.Errorf("Object path should be a string") + } + val ,err = n.filter.execute() + if err != nil { + return nil, err + } + filter, ok := val.(string) + if !ok { + return nil, fmt.Errorf("Object filter should be a string") + } + obj,err := cmd.GetDevicesInfo(path,filter) + if err != nil { + return nil, err + } + cmd.DisplayObject(obj) + return obj,nil +} + type selectObjectNode struct { path node } diff --git a/CLI/controllers/commandController.go b/CLI/controllers/commandController.go index f78a6d3a7..616f145fc 100755 --- a/CLI/controllers/commandController.go +++ b/CLI/controllers/commandController.go @@ -70,6 +70,14 @@ func ObjectUrl(path string, depth int) (string, error) { return fmt.Sprintf(url + "/" + suffix), nil } +func GetObjectDevice(path string) (string,error) { + object := strings.Split(path,"/") + if(len(object) != 7) { + return "", fmt.Errorf("Path is not a device"); + } + return object[6], nil +} + func IsTemplate(path string) bool { if strings.HasPrefix(path, "/Logical/ObjectTemplates/") { return true @@ -142,6 +150,48 @@ func GetObject(path string) (map[string]any, error) { return GetObjectWithChildren(path, 0) } +func GetDevicesInfo(path string,filters string) (map[string]any, error) { + device,err := GetObjectDevice(path) + if err != nil { + return nil, err + } + url,err := DevicesUrl(device,filters) + if err != nil { + return nil, err + } + resp, err := RequestAPI("GET", url, nil, http.StatusOK) + if err != nil { + if resp != nil && resp.status == http.StatusNotFound { + return nil, nil + } + return nil, err + } + obj, ok := resp.body["data"].(map[string]any) + if !ok { + return nil, fmt.Errorf("invalid response from API on GET %s", url) + } + return obj, nil +} +func DevicesUrl(path,filters string) (string, error){ + query := GenerateQuery(filters) + device := strings.Split(filters, ".")[0] + if device == "devices" { + return "/api/Devices?group_name="+path+query,nil + } + return "", fmt.Errorf("invalid object path") + +} +func GenerateQuery(filters string) (string) { + queries:= strings.Split(filters,".") + result:="" + for _,query := range queries { + if strings.Contains(query,"="){ + result+="&"+query + } + } + return result +} + func Ls(path string) ([]string, error) { n, err := Tree(path, 1) if err != nil { @@ -622,7 +672,7 @@ func Help(entry string) { case "ls", "pwd", "print", "cd", "tree", "get", "clear", "lsog", "grep", "for", "while", "if", "env", "cmds", "var", "unset", "selection", "camera", "ui", "hc", "drawable", - "link", "unlink", "draw", "getu", "getslot", "undraw", + "link", "unlink", "draw", "getu", "getslot","undraw", "lsenterprise": path = "./other/man/" + entry + ".md" diff --git a/CLI/parser.go b/CLI/parser.go index a1baa07e5..eeb788cfd 100644 --- a/CLI/parser.go +++ b/CLI/parser.go @@ -621,7 +621,14 @@ func (p *parser) parseLs() node { func (p *parser) parseGet() node { defer un(trace(p, "get")) - return &getObjectNode{p.parsePath("")} + path := p.parsePath("") + if p.commandEnd() { + return &getObjectNode{path} + } + + obj := p.parseString("") + return &getPNode{path,obj} + } func (p *parser) parseGetU() node { From d348645e195baeb4d23c2eee71f8371efc1dd185 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Wed, 9 Aug 2023 14:27:17 +0200 Subject: [PATCH 18/35] fix(cli): add error message if device not found --- CLI/controllers/commandController.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CLI/controllers/commandController.go b/CLI/controllers/commandController.go index 616f145fc..ff81c2b0d 100755 --- a/CLI/controllers/commandController.go +++ b/CLI/controllers/commandController.go @@ -73,7 +73,7 @@ func ObjectUrl(path string, depth int) (string, error) { func GetObjectDevice(path string) (string,error) { object := strings.Split(path,"/") if(len(object) != 7) { - return "", fmt.Errorf("Path is not a device"); + return "", fmt.Errorf(object[len(object)-1] +" is not a device"); } return object[6], nil } @@ -162,7 +162,7 @@ func GetDevicesInfo(path string,filters string) (map[string]any, error) { resp, err := RequestAPI("GET", url, nil, http.StatusOK) if err != nil { if resp != nil && resp.status == http.StatusNotFound { - return nil, nil + return nil, fmt.Errorf("Devices not found") } return nil, err } From f9fb0166ff3bd4dab5c43ecac13a5ddcfca322c8 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Wed, 9 Aug 2023 18:03:10 +0200 Subject: [PATCH 19/35] feat(cli): binding info from object and devices --- ARANGO_API/handlers/devices.go | 8 +-- ARANGO_API/services/router.go | 8 +-- ARANGO_API/swagger.json | 6 +- BFF/controllers/devices.go | 89 ++++++++++++++++++++++++++++ BFF/handlers/devices.go | 67 +++++++++++++++++++-- BFF/services/router.go | 10 ++-- BFF/swagger.json | 85 +++++++++++++++++++++++++- CLI/controllers/commandController.go | 65 +++++++++++++------- 8 files changed, 294 insertions(+), 44 deletions(-) create mode 100644 BFF/controllers/devices.go diff --git a/ARANGO_API/handlers/devices.go b/ARANGO_API/handlers/devices.go index fc6e95d8a..59b9f37f8 100644 --- a/ARANGO_API/handlers/devices.go +++ b/ARANGO_API/handlers/devices.go @@ -8,7 +8,7 @@ import ( "github.com/gin-gonic/gin" ) -// swagger:operation GET /Devices Devices Devices +// swagger:operation GET /devices Devices Devices // Get Devices list // // --- @@ -61,7 +61,7 @@ func GetDevices(c *gin.Context) { c.IndentedJSON(http.StatusOK, devices) } -// swagger:operation GET /Devices/ConnecteTo/{device} Devices GetDevicesConnectedTo +// swagger:operation GET /devices/ConnecteTo/{device} Devices GetDevicesConnectedTo // Get Devices connected to a device // // --- @@ -120,7 +120,7 @@ func GetDevicesConnectedTo(c *gin.Context) { c.IndentedJSON(http.StatusOK, devices) } -// swagger:operation POST /Devices Devices CreateDevices +// swagger:operation POST /devices Devices CreateDevices // Create new Devices // // --- @@ -168,7 +168,7 @@ func PostDevices(c *gin.Context) { c.IndentedJSON(http.StatusCreated, result) } -// swagger:operation DELETE /Devices/{device} Devices DeleteDevices +// swagger:operation DELETE /devices/{device} Devices DeleteDevices // Delete Devices by key // // --- diff --git a/ARANGO_API/services/router.go b/ARANGO_API/services/router.go index 5294349a4..9b2ebcccc 100644 --- a/ARANGO_API/services/router.go +++ b/ARANGO_API/services/router.go @@ -41,10 +41,10 @@ func InitRouter(db driver.Database, addr string) *gin.Engine { router.Use(DBMiddleware(db, addr)) proteted := router.Group("/api") //proteted.Use(JwtAuthMiddleware()) - proteted.GET("/Devices", handlers.GetDevices) - proteted.POST("/Devices", handlers.PostDevices) - proteted.DELETE("/Devices/:key", handlers.DeleteDevice) - proteted.GET("/Devices/ConnecteTo/:key", handlers.GetDevicesConnectedTo) + proteted.GET("/:devices", handlers.GetDevices) + proteted.POST("/:devices", handlers.PostDevices) + proteted.DELETE(":devices/:key", handlers.DeleteDevice) + proteted.GET(":devices/ConnecteTo/:key", handlers.GetDevicesConnectedTo) proteted.GET("/Connections", handlers.GetConnection) proteted.POST("/Connections", handlers.PostConnection) diff --git a/ARANGO_API/swagger.json b/ARANGO_API/swagger.json index 816cf9753..a28b4a59d 100644 --- a/ARANGO_API/swagger.json +++ b/ARANGO_API/swagger.json @@ -149,7 +149,7 @@ } } }, - "/Devices": { + "/devices": { "get": { "security": [ { @@ -247,7 +247,7 @@ } } }, - "/Devices/ConnecteTo/{device}": { + "/devices/ConnecteTo/{device}": { "get": { "security": [ { @@ -312,7 +312,7 @@ } } }, - "/Devices/{device}": { + "/devices/{device}": { "delete": { "security": [ { diff --git a/BFF/controllers/devices.go b/BFF/controllers/devices.go new file mode 100644 index 000000000..e0802d21c --- /dev/null +++ b/BFF/controllers/devices.go @@ -0,0 +1,89 @@ +package controllers + +import ( + + "net/http" + "ogree-bff/utils/token" + + "github.com/gin-gonic/gin" +) + + + +func DeviceBindingObject(c *gin.Context,database string) { + + objAttr:= c.Param("objAttr") + + obj := c.Param("obj") + + //MONGO Check + mongoURL, ok := c.Value("mongo").(string) + if !ok { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Failed to get api connection"}) + return + } + key := token.ExtractToken(c) + mongoResp,err := Send("GET",mongoURL+"/api/objects/"+obj,"",key,nil) + if err != nil { + if mongoResp != nil { + result := GetJSONBody(mongoResp) + c.IndentedJSON(mongoResp.StatusCode,result.Message) + return + } + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + mongoBody:=GetJSONBody(mongoResp) + if mongoBody.StatusCode != http.StatusOK { + c.IndentedJSON(mongoBody.StatusCode,mongoBody.Message) + return + } + mongoDataResult := mongoBody.Message.(map[string]interface{}) + mongoResult := mongoDataResult["data"].(map[string]interface{}) + if mongoResult["category"] != "device"{ + c.IndentedJSON(http.StatusBadRequest, gin.H{"message":obj +" is not a device"}) + return + } + mongoAttr := mongoResult["attributes"].(map[string]interface{}) + if mongoAttr[objAttr] == nil && mongoResult[objAttr] == nil { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message":obj +" has not attributes :" + objAttr}) + return + } + var attributeNeed string + if mongoResult[objAttr] != nil { + attributeNeed = mongoResult[objAttr].(string) + }else{ + attributeNeed = mongoAttr[objAttr].(string) + } + + //ARANGO + deviceAttr:= c.Param("deviceAttr") + deviceURL, ok := c.Value(database).(string) + if !ok { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Failed to get api connection"}) + return + } + query := GetQueryString(c) + if query == "" { + query +="?"+deviceAttr+"="+attributeNeed + }else{ + query +="&"+deviceAttr+"="+attributeNeed + } + + deviceResp,err := Send("GET",deviceURL+"/api/devices",query,key,nil) + if err != nil { + if deviceResp != nil { + result := GetJSONBody(deviceResp) + c.IndentedJSON(deviceResp.StatusCode,result.Message) + return + } + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + result := GetJSONBody(deviceResp) + c.IndentedJSON(deviceResp.StatusCode, result.Message) + return + + + +} \ No newline at end of file diff --git a/BFF/handlers/devices.go b/BFF/handlers/devices.go index 1503c62c8..77c454273 100644 --- a/BFF/handlers/devices.go +++ b/BFF/handlers/devices.go @@ -6,7 +6,7 @@ import ( "github.com/gin-gonic/gin" ) -// swagger:operation GET /Devices Devices Devices +// swagger:operation GET /devices Devices Devices // Get Devices list // // --- @@ -49,7 +49,7 @@ func GetDevices(c *gin.Context) { controllers.Get(c,"arango") } -// swagger:operation GET /Devices/ConnecteTo/{device} Devices GetDevicesConnectedTo +// swagger:operation GET /devices/ConnecteTo/{device} Devices GetDevicesConnectedTo // Get Devices connected to a device // // --- @@ -95,7 +95,7 @@ func GetDevices(c *gin.Context) { func GetDevicesConnectedTo(c *gin.Context) { controllers.Get(c,"arango") } -// swagger:operation POST /Devices Devices CreateDevices +// swagger:operation POST /devices Devices CreateDevices // Create new Devices // // --- @@ -123,7 +123,7 @@ func CreateDevices(c *gin.Context) { controllers.Post(c,"arango") } -// swagger:operation DELETE /Devices/{device} Devices DeleteDevices +// swagger:operation DELETE /devices/{device} Devices DeleteDevices // Delete Devices by key // // --- @@ -240,4 +240,63 @@ func CreateConnections(c *gin.Context){ // "$ref": "#/definitions/ErrorResponse" func DeleteConnections(c *gin.Context){ controllers.Delete(c,"arango") +} + + + +// swagger:operation GET /devices/{obj}/objAttr/{objAttr}/deviceAttr/{deviceAttr} Devices GetDeviceBindingObject +// Get Devices list +// +// --- +// parameters: +// - name: obj +// in: path +// description: object for binding +// required: true +// type: string +// - name: objAttr +// in: path +// description: object attribute for binding +// required: true +// type: string +// - name: deviceAttr +// in: path +// description: devices attribute for binding +// required: true +// type: string +// - name: _key +// in: query +// description: Key of device +// required: false +// type: string +// - name: _name +// in: query +// description: Name of device +// required: false +// type: string +// - name: group_name +// in: query +// description: Group_name of device +// required: false +// type: string +// - name: serial +// in: query +// description: Serial number of device +// required: false +// type: string +// security: +// - Bearer: [] +// responses: +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func GetDeviceBindingObject(c*gin.Context){ + controllers.DeviceBindingObject(c,"arango") } \ No newline at end of file diff --git a/BFF/services/router.go b/BFF/services/router.go index f8d01a3ad..370c0f320 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -39,14 +39,16 @@ func APIMiddleware(apiList []models.API) gin.HandlerFunc { } func initDevices(protected, unprotected *gin.RouterGroup){ - protected.GET("/Devices",handlers.GetDevices) - protected.GET("/Devices/ConnecteTo/:key",handlers.GetDevicesConnectedTo) - protected.POST("/Devices",handlers.CreateDevices) - protected.DELETE("/Devices/:id",handlers.DeleteDevice) + protected.GET("/devices",handlers.GetDevices) + protected.GET("/devices/ConnecteTo/:key",handlers.GetDevicesConnectedTo) + protected.POST("/devices",handlers.CreateDevices) + protected.DELETE("/devices/:id",handlers.DeleteDevice) protected.GET("/Connections",handlers.GetConnections) protected.POST("/Connections",handlers.CreateConnections) protected.DELETE("/Connections/:id",handlers.DeleteConnections) + + protected.GET("/devices/:obj/objAttr/:objAttr/deviceAttr/:deviceAttr",handlers.GetDeviceBindingObject) } func initAuth(protected, unprotected *gin.RouterGroup){ diff --git a/BFF/swagger.json b/BFF/swagger.json index 9fd40d01f..4a0527563 100644 --- a/BFF/swagger.json +++ b/BFF/swagger.json @@ -149,7 +149,7 @@ } } }, - "/Devices": { + "/devices": { "get": { "security": [ { @@ -247,7 +247,7 @@ } } }, - "/Devices/ConnecteTo/{device}": { + "/devices/ConnecteTo/{device}": { "get": { "security": [ { @@ -312,7 +312,7 @@ } } }, - "/Devices/{device}": { + "/devices/{device}": { "delete": { "security": [ { @@ -353,6 +353,85 @@ } } }, + "/devices/{obj}/objAttr/{objAttr}/deviceAttr/{deviceAttr}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get Devices list", + "tags": [ + "Devices" + ], + "operationId": "GetDeviceBindingObject", + "parameters": [ + { + "type": "string", + "description": "object for binding", + "name": "obj", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "object attribute for binding", + "name": "objAttr", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "devices attribute for binding", + "name": "deviceAttr", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Key of device", + "name": "_key", + "in": "query" + }, + { + "type": "string", + "description": "Name of device", + "name": "_name", + "in": "query" + }, + { + "type": "string", + "description": "Group_name of device", + "name": "group_name", + "in": "query" + }, + { + "type": "string", + "description": "Serial number of device", + "name": "serial", + "in": "query" + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, "/domains/bulk": { "post": { "security": [ diff --git a/CLI/controllers/commandController.go b/CLI/controllers/commandController.go index ff81c2b0d..9bb1af426 100755 --- a/CLI/controllers/commandController.go +++ b/CLI/controllers/commandController.go @@ -70,14 +70,6 @@ func ObjectUrl(path string, depth int) (string, error) { return fmt.Sprintf(url + "/" + suffix), nil } -func GetObjectDevice(path string) (string,error) { - object := strings.Split(path,"/") - if(len(object) != 7) { - return "", fmt.Errorf(object[len(object)-1] +" is not a device"); - } - return object[6], nil -} - func IsTemplate(path string) bool { if strings.HasPrefix(path, "/Logical/ObjectTemplates/") { return true @@ -149,20 +141,48 @@ func PollObject(path string) (map[string]any, error) { func GetObject(path string) (map[string]any, error) { return GetObjectWithChildren(path, 0) } - +func ObjectAttributes(path string)(string, error){ + attr := strings.Split(path, "%"); + if(len(attr) !=2 ){ + return "name",nil + } + return attr[1],nil +} +func DevicesAttrs(devices string)(string, error){ + attr := strings.Split(strings.Split(devices,".")[0],"%"); + if(len(attr) !=2 ){ + return "group_name",nil + } + return attr[1],nil +} +func removeFirstOccurrence(input string, pattern string) string { + inputs := strings.Split(input,pattern) + if len(inputs) <3 { + return input + } + return strings.Join(inputs[2:],".") +} func GetDevicesInfo(path string,filters string) (map[string]any, error) { - device,err := GetObjectDevice(path) + + objAttr ,err:= ObjectAttributes(path) + if err != nil { + return nil, err + } + devicesAttr ,err:= DevicesAttrs(filters) if err != nil { return nil, err } - url,err := DevicesUrl(device,filters) + path = removeFirstOccurrence(path,"/") + + url,err := DevicesUrl(strings.Split(path,"%")[0],objAttr,devicesAttr,filters) if err != nil { return nil, err } resp, err := RequestAPI("GET", url, nil, http.StatusOK) if err != nil { if resp != nil && resp.status == http.StatusNotFound { - return nil, fmt.Errorf("Devices not found") + device := strings.Split(strings.Split(filters, ".")[0],"%")[0] + return nil, fmt.Errorf(device+" not found") } return nil, err } @@ -172,21 +192,22 @@ func GetDevicesInfo(path string,filters string) (map[string]any, error) { } return obj, nil } -func DevicesUrl(path,filters string) (string, error){ - query := GenerateQuery(filters) - device := strings.Split(filters, ".")[0] - if device == "devices" { - return "/api/Devices?group_name="+path+query,nil - } - return "", fmt.Errorf("invalid object path") +func DevicesUrl(path,objAttr,devAttr,filters string) (string, error){ + query := GenerateDeviceQuery(filters) + device := strings.Split(strings.Split(filters, ".")[0],"%")[0] + return "/api/"+device+"/"+path+"/objAttr/"+objAttr+"/deviceAttr/"+devAttr+query,nil } -func GenerateQuery(filters string) (string) { +func GenerateDeviceQuery(filters string) (string) { queries:= strings.Split(filters,".") result:="" for _,query := range queries { if strings.Contains(query,"="){ - result+="&"+query + if result == "" { + result+= "?"+query + }else{ + result+="&"+query + } } } return result @@ -672,7 +693,7 @@ func Help(entry string) { case "ls", "pwd", "print", "cd", "tree", "get", "clear", "lsog", "grep", "for", "while", "if", "env", "cmds", "var", "unset", "selection", "camera", "ui", "hc", "drawable", - "link", "unlink", "draw", "getu", "getslot","undraw", + "link", "unlink", "draw", "getu", "getslot", "undraw", "lsenterprise": path = "./other/man/" + entry + ".md" From a6aaded9736898b636496b074e372758ff2b2663 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Wed, 9 Aug 2023 18:43:06 +0200 Subject: [PATCH 20/35] fix(bff): rename database and changing route for binding --- BFF/controllers/devices.go | 57 ++-- BFF/handlers/about.go | 36 +-- BFF/handlers/auth.go | 108 ++++---- BFF/handlers/devices.go | 198 ++++++++------ BFF/handlers/flutterApp.go | 85 +++--- BFF/handlers/object.go | 383 +++++++++++++++------------ BFF/handlers/organization.go | 159 ++++++----- BFF/main.go | 4 +- BFF/services/router.go | 2 +- BFF/swagger.json | 2 +- CLI/controllers/commandController.go | 2 +- 11 files changed, 578 insertions(+), 458 deletions(-) diff --git a/BFF/controllers/devices.go b/BFF/controllers/devices.go index e0802d21c..22439156b 100644 --- a/BFF/controllers/devices.go +++ b/BFF/controllers/devices.go @@ -1,80 +1,79 @@ package controllers import ( - "net/http" "ogree-bff/utils/token" "github.com/gin-gonic/gin" ) +func DeviceBindingObject(c *gin.Context) { + entity := c.Param("entity") + deviceURL, ok := c.Value(entity).(string) + if !ok { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": entity + " has not database"}) + return + } + objAttr := c.Param("objAttr") -func DeviceBindingObject(c *gin.Context,database string) { - - objAttr:= c.Param("objAttr") - obj := c.Param("obj") //MONGO Check - mongoURL, ok := c.Value("mongo").(string) + mongoURL, ok := c.Value("objects").(string) if !ok { c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Failed to get api connection"}) - return + return } key := token.ExtractToken(c) - mongoResp,err := Send("GET",mongoURL+"/api/objects/"+obj,"",key,nil) + mongoResp, err := Send("GET", mongoURL+"/api/objects/"+obj, "", key, nil) if err != nil { if mongoResp != nil { result := GetJSONBody(mongoResp) - c.IndentedJSON(mongoResp.StatusCode,result.Message) + c.IndentedJSON(mongoResp.StatusCode, result.Message) return } c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) return } - mongoBody:=GetJSONBody(mongoResp) + mongoBody := GetJSONBody(mongoResp) if mongoBody.StatusCode != http.StatusOK { - c.IndentedJSON(mongoBody.StatusCode,mongoBody.Message) + c.IndentedJSON(mongoBody.StatusCode, mongoBody.Message) return } mongoDataResult := mongoBody.Message.(map[string]interface{}) mongoResult := mongoDataResult["data"].(map[string]interface{}) - if mongoResult["category"] != "device"{ - c.IndentedJSON(http.StatusBadRequest, gin.H{"message":obj +" is not a device"}) + if mongoResult["category"] != "device" { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": obj + " is not a device"}) return } mongoAttr := mongoResult["attributes"].(map[string]interface{}) - if mongoAttr[objAttr] == nil && mongoResult[objAttr] == nil { - c.IndentedJSON(http.StatusBadRequest, gin.H{"message":obj +" has not attributes :" + objAttr}) + if mongoAttr[objAttr] == nil && mongoResult[objAttr] == nil { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": obj + " has not attributes :" + objAttr}) return } var attributeNeed string if mongoResult[objAttr] != nil { attributeNeed = mongoResult[objAttr].(string) - }else{ + } else { attributeNeed = mongoAttr[objAttr].(string) } //ARANGO - deviceAttr:= c.Param("deviceAttr") - deviceURL, ok := c.Value(database).(string) - if !ok { - c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": "Failed to get api connection"}) - return - } + deviceAttr := c.Param("deviceAttr") + query := GetQueryString(c) if query == "" { - query +="?"+deviceAttr+"="+attributeNeed - }else{ - query +="&"+deviceAttr+"="+attributeNeed + query += "?" + deviceAttr + "=" + attributeNeed + } else { + query += "&" + deviceAttr + "=" + attributeNeed } - deviceResp,err := Send("GET",deviceURL+"/api/devices",query,key,nil) + deviceResp, err := Send("GET", deviceURL+"/api/devices", query, key, nil) if err != nil { if deviceResp != nil { result := GetJSONBody(deviceResp) - c.IndentedJSON(deviceResp.StatusCode,result.Message) + c.IndentedJSON(deviceResp.StatusCode, result.Message) return } c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) @@ -84,6 +83,4 @@ func DeviceBindingObject(c *gin.Context,database string) { c.IndentedJSON(deviceResp.StatusCode, result.Message) return - - -} \ No newline at end of file +} diff --git a/BFF/handlers/about.go b/BFF/handlers/about.go index acb68ba38..23ba9140e 100644 --- a/BFF/handlers/about.go +++ b/BFF/handlers/about.go @@ -2,7 +2,7 @@ package handlers import ( "ogree-bff/controllers" - + "github.com/gin-gonic/gin" ) @@ -11,15 +11,18 @@ import ( // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // responses: -// '200': -// description: 'Request is valid.' -// '504': -// description: Server error. -func GetStats(c *gin.Context){ - controllers.Get(c,"mongo") +// +// '200': +// description: 'Request is valid.' +// '504': +// description: Server error. +func GetStats(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation GET /version About GetAPIVersion @@ -27,12 +30,15 @@ func GetStats(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // responses: -// '200': -// description: 'OK. A response body will be returned with -// version details.' -func GetAPIVersion(c *gin.Context){ - controllers.Get(c,"mongo") -} \ No newline at end of file +// +// '200': +// description: 'OK. A response body will be returned with +// version details.' +func GetAPIVersion(c *gin.Context) { + controllers.Get(c, "objects") +} diff --git a/BFF/handlers/auth.go b/BFF/handlers/auth.go index fc7ae86bc..90845fa51 100644 --- a/BFF/handlers/auth.go +++ b/BFF/handlers/auth.go @@ -2,7 +2,7 @@ package handlers import ( "ogree-bff/controllers" - + "github.com/gin-gonic/gin" ) @@ -20,15 +20,17 @@ import ( // required: true // format: object // example: '{"email": "user@test.com", "password": "secret123"}' +// // responses: -// '200': -// description: Authenticated -// '400': -// description: Bad request -// '500': -// description: Internal server error -func Login(c *gin.Context){ - controllers.Post(c,"mongo") +// +// '200': +// description: Authenticated +// '400': +// description: Bad request +// '500': +// description: Internal server error +func Login(c *gin.Context) { + controllers.Post(c, "objects") } // swagger:operation GET /token/valid Authentication VerifyToken @@ -36,28 +38,32 @@ func Login(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // responses: -// '200': -// description: Token is valid. -// '403': -// description: Unauthorized -// '500': -// description: Internal server error -func ValidToken(c *gin.Context){ - controllers.Get(c,"mongo") +// +// '200': +// description: Token is valid. +// '403': +// description: Unauthorized +// '500': +// description: Internal server error +func ValidToken(c *gin.Context) { + controllers.Get(c, "objects") } - // swagger:operation POST /users/password/change Authentication ModifyUserPassword // For logged in user to change its own password. // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: body // in: body @@ -67,15 +73,17 @@ func ValidToken(c *gin.Context){ // example: '{"currentPassword": "myOldPassword", "newPassword": "myNewPassword"}' // // responses: -// '200': -// description: Password changed -// '400': -// description: Bad request -// '500': -// description: Internal server error -func ModifyUserPassword(c *gin.Context){ - controllers.Post(c,"mongo") +// +// '200': +// description: Password changed +// '400': +// description: Bad request +// '500': +// description: Internal server error +func ModifyUserPassword(c *gin.Context) { + controllers.Post(c, "objects") } + // swagger:operation POST /users/password/reset Authentication ResetUserPassword // Reset password after forgot. // For user that first called forgot enpoint to change its password. @@ -83,8 +91,10 @@ func ModifyUserPassword(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: body // in: body @@ -94,22 +104,25 @@ func ModifyUserPassword(c *gin.Context){ // example: '{"newPassword": "myNewPassword"}' // // responses: -// '200': -// description: Password changed -// '400': -// description: Bad request -// '500': -// description: Internal server error -func ResetUserPassword(c *gin.Context){ - controllers.Post(c,"mongo") +// +// '200': +// description: Password changed +// '400': +// description: Bad request +// '500': +// description: Internal server error +func ResetUserPassword(c *gin.Context) { + controllers.Post(c, "objects") } + // swagger:operation POST /users/password/forgot Authentication UserForgotPassword // Forgot my password. // Public endpoint to request a reset of a user's password (forgot my password). // If the email is valid, an email with a reset token/link will be sent to the user. // --- // produces: -// - application/json +// - application/json +// // parameters: // - name: body // in: body @@ -119,12 +132,13 @@ func ResetUserPassword(c *gin.Context){ // example: '{"email": "user@test.com"}' // // responses: -// '200': -// description: request processed. If account exists, an email with a reset token is sent -// '400': -// description: Bad request -// '500': -// description: Internal server error -func UserForgotPassword(c *gin.Context){ - controllers.Post(c,"mongo") -} \ No newline at end of file +// +// '200': +// description: request processed. If account exists, an email with a reset token is sent +// '400': +// description: Bad request +// '500': +// description: Internal server error +func UserForgotPassword(c *gin.Context) { + controllers.Post(c, "objects") +} diff --git a/BFF/handlers/devices.go b/BFF/handlers/devices.go index 77c454273..cad60b5c3 100644 --- a/BFF/handlers/devices.go +++ b/BFF/handlers/devices.go @@ -46,7 +46,7 @@ import ( // "$ref": "#/definitions/ErrorResponse" func GetDevices(c *gin.Context) { - controllers.Get(c,"arango") + controllers.Get(c, "devices") } // swagger:operation GET /devices/ConnecteTo/{device} Devices GetDevicesConnectedTo @@ -79,28 +79,33 @@ func GetDevices(c *gin.Context) { // description: Serial number of device // required: false // type: string +// // security: // - Bearer: [] +// // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func GetDevicesConnectedTo(c *gin.Context) { - controllers.Get(c,"arango") + controllers.Get(c, "devices") } + // swagger:operation POST /devices Devices CreateDevices // Create new Devices // // --- // security: // - Bearer: [] +// // parameters: // - name: body // in: body @@ -108,19 +113,21 @@ func GetDevicesConnectedTo(c *gin.Context) { // required: true // format: object // example: '{"_name": "server", "group_name": "exwipen22","created": "2022-07-18"}' +// // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func CreateDevices(c *gin.Context) { - controllers.Post(c,"arango") + controllers.Post(c, "devices") } // swagger:operation DELETE /devices/{device} Devices DeleteDevices @@ -133,21 +140,24 @@ func CreateDevices(c *gin.Context) { // description: device looking for // required: true // type: string +// // security: -// - Bearer: [] +// - Bearer: [] +// // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -func DeleteDevice(c *gin.Context){ - controllers.Delete(c,"arango") +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func DeleteDevice(c *gin.Context) { + controllers.Delete(c, "devices") } // swagger:operation GET /Connections Devices GetConnections @@ -170,28 +180,33 @@ func DeleteDevice(c *gin.Context){ // description: To witch device // required: false // type: string +// // security: // - Bearer: [] +// // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -func GetConnections(c *gin.Context){ - controllers.Get(c,"arango") +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func GetConnections(c *gin.Context) { + controllers.Get(c, "devices") } + // swagger:operation POST /Connections Devices CreateConnection // Create new Connection // // --- // security: // - Bearer: [] +// // parameters: // - name: body // in: body @@ -199,19 +214,21 @@ func GetConnections(c *gin.Context){ // required: true // format: object // example: '{"_from": "devices/123", "_to": "devices/111"}' +// // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -func CreateConnections(c *gin.Context){ - controllers.Post(c,"arango") +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func CreateConnections(c *gin.Context) { + controllers.Post(c, "devices") } // swagger:operation DELETE /Connections/{connection} Devices DeleteConnection @@ -220,6 +237,7 @@ func CreateConnections(c *gin.Context){ // --- // security: // - Bearer: [] +// // parameters: // - name: connection // in: path @@ -228,23 +246,22 @@ func CreateConnections(c *gin.Context){ // type: string // // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -func DeleteConnections(c *gin.Context){ - controllers.Delete(c,"arango") +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func DeleteConnections(c *gin.Context) { + controllers.Delete(c, "devices") } - - -// swagger:operation GET /devices/{obj}/objAttr/{objAttr}/deviceAttr/{deviceAttr} Devices GetDeviceBindingObject +// swagger:operation GET /devices/{entity}/{obj}/{objAttr}/{deviceAttr} Devices GetDeviceBindingObject // Get Devices list // // --- @@ -284,19 +301,24 @@ func DeleteConnections(c *gin.Context){ // description: Serial number of device // required: false // type: string +// // security: // - Bearer: [] +// // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" -func GetDeviceBindingObject(c*gin.Context){ - controllers.DeviceBindingObject(c,"arango") -} \ No newline at end of file +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" +func GetDeviceBindingObject(c *gin.Context) { + + controllers.DeviceBindingObject(c) + +} diff --git a/BFF/handlers/flutterApp.go b/BFF/handlers/flutterApp.go index b457fd05e..17793aa73 100644 --- a/BFF/handlers/flutterApp.go +++ b/BFF/handlers/flutterApp.go @@ -29,8 +29,8 @@ import ( // '500': // description: 'Internal server error.' -func GetProjects(c *gin.Context){ - controllers.Get(c,"mongo") +func GetProjects(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation POST /projects FlutterApp CreateProjects @@ -38,8 +38,10 @@ func GetProjects(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: body // in: body @@ -51,23 +53,28 @@ func GetProjects(c *gin.Context){ // example: '{"attributes":["domain"],"authorLastUpdate":"helder","dateRange":"01/01/2023-02/02/2023", // "lastUpdate":"02/02/2023","name":"test 1","namespace":"physical","objects":["siteB"],"showAvg":false, // "showSum":false,"permissions":["user@test.com","admin"]}' +// // responses: -// '200': -// description: 'Project successfully created.' -// '400': -// description: 'Bad Request. Invalid project format.' -// '500': -// description: 'Internal server error.' -func CreateProjects(c *gin.Context){ - controllers.Post(c,"mongo") +// +// '200': +// description: 'Project successfully created.' +// '400': +// description: 'Bad Request. Invalid project format.' +// '500': +// description: 'Internal server error.' +func CreateProjects(c *gin.Context) { + controllers.Post(c, "objects") } + // swagger:operation PUT /projects/{ProjectID} FlutterApp UpdateProjects // Replace the data of an existing project. // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: ProjectID // in: path @@ -85,15 +92,17 @@ func CreateProjects(c *gin.Context){ // example: '{"attributes":["domain"],"authorLastUpdate":"helder","dateRange":"01/01/2023-02/02/2023", // "lastUpdate":"02/02/2023","name":"test 1","namespace":"physical","objects":["siteB"],"showAvg":false, // "showSum":false,"permissions":["user@test.com","admin"]}' +// // responses: -// '200': -// description: Project successfully updated. -// '400': -// description: Bad Request. Invalid project format. -// '500': -// description: Internal server error -func UpdateProjects(c *gin.Context){ - controllers.Put(c,"mongo") +// +// '200': +// description: Project successfully updated. +// '400': +// description: Bad Request. Invalid project format. +// '500': +// description: Internal server error +func UpdateProjects(c *gin.Context) { + controllers.Put(c, "objects") } // swagger:operation DELETE /projects/{ProjectID} FlutterApp DeleteProjects @@ -101,22 +110,26 @@ func UpdateProjects(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: -// - name: ProjectID -// in: path -// description: 'ID of the project to delete.' -// required: true -// type: string -// default: "1234" +// - name: ProjectID +// in: path +// description: 'ID of the project to delete.' +// required: true +// type: string +// default: "1234" +// // responses: -// '200': -// description: Project successfully updated. -// '404': -// description: Not Found. Invalid project ID. -// '500': -// description: Internal server error -func DeleteProjects(c *gin.Context){ - controllers.Delete(c,"mongo") -} \ No newline at end of file +// +// '200': +// description: Project successfully updated. +// '404': +// description: Not Found. Invalid project ID. +// '500': +// description: Internal server error +func DeleteProjects(c *gin.Context) { + controllers.Delete(c, "objects") +} diff --git a/BFF/handlers/object.go b/BFF/handlers/object.go index e7393c963..08fb627c4 100644 --- a/BFF/handlers/object.go +++ b/BFF/handlers/object.go @@ -11,8 +11,10 @@ import ( // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: entity // in: path @@ -27,15 +29,17 @@ import ( // in: body // required: true // default: {} +// // responses: -// '201': -// description: 'Created. A response body will be returned with -// a meaningful message.' -// '400': -// description: 'Bad request. A response body with an error -// message will be returned.' -func CreateObject(c *gin.Context){ - controllers.Post(c,"mongo") +// +// '201': +// description: 'Created. A response body will be returned with +// a meaningful message.' +// '400': +// description: 'Bad request. A response body with an error +// message will be returned.' +func CreateObject(c *gin.Context) { + controllers.Post(c, "objects") } // swagger:operation GET /objects/{hierarchyName} Objects GetGenericObject @@ -45,8 +49,10 @@ func CreateObject(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: hierarchyName // in: path @@ -64,23 +70,28 @@ func CreateObject(c *gin.Context){ // in: query // description: 'filter objects by lastUpdated <= endDate. // Format: yyyy-mm-dd' +// // responses: +// // '200': // description: 'Found. A response body will be returned with // a meaningful message.' // '404': // description: Not Found. An error message will be returned. -func GetGenericObject(c *gin.Context){ - controllers.Get(c,"mongo") +func GetGenericObject(c *gin.Context) { + controllers.Get(c, "objects") } + // swagger:operation GET /{entity}/{IdOrHierarchyName} Objects GetEntity // Gets an Object of the given entity. // The ID or hierarchy name must be provided in the URL parameter. // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: entity // in: path @@ -110,16 +121,18 @@ func GetGenericObject(c *gin.Context){ // in: query // description: 'filter objects by lastUpdated <= endDate. // Format: yyyy-mm-dd' +// // responses: -// '200': -// description: 'Found. A response body will be returned with -// a meaningful message.' -// '400': -// description: Bad request. An error message will be returned. -// '404': -// description: Not Found. An error message will be returned. -func GetEntity(c *gin.Context){ - controllers.Get(c,"mongo") +// +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '400': +// description: Bad request. An error message will be returned. +// '404': +// description: Not Found. An error message will be returned. +func GetEntity(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation GET /{entity} Objects GetAllEntities @@ -128,8 +141,10 @@ func GetEntity(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: entity // in: path @@ -154,13 +169,14 @@ func GetEntity(c *gin.Context){ // Format: yyyy-mm-dd' // // responses: -// '200': -// description: 'Found. A response body will be returned with -// a meaningful message.' -// '404': -// description: Nothing Found. An error message will be returned. -func GetAllEntities(c *gin.Context){ - controllers.Get(c,"mongo") +// +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: Nothing Found. An error message will be returned. +func GetAllEntities(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation DELETE /{entity}/{IdOrHierarchyName} Objects DeleteObject @@ -168,8 +184,10 @@ func GetAllEntities(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: entity // in: path @@ -189,13 +207,14 @@ func GetAllEntities(c *gin.Context){ // default: "siteA" // // responses: -// '204': -// description: 'Successfully deleted object. -// No response body will be returned' -// '404': -// description: Not found. An error message will be returned -func DeleteObject(c *gin.Context){ - controllers.Delete(c,"mongo") +// +// '204': +// description: 'Successfully deleted object. +// No response body will be returned' +// '404': +// description: Not found. An error message will be returned +func DeleteObject(c *gin.Context) { + controllers.Delete(c, "objects") } // swagger:operation PATCH /{entity}/{IdOrHierarchyName} Objects PartialUpdateObject @@ -206,8 +225,10 @@ func DeleteObject(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: entity // in: path @@ -227,15 +248,16 @@ func DeleteObject(c *gin.Context){ // default: "siteA" // // responses: -// '200': -// description: 'Updated. A response body will be returned with -// a meaningful message.' -// '400': -// description: Bad request. An error message will be returned. -// '404': -// description: Not Found. An error message will be returned. -func PartialUpdateObject(c *gin.Context){ - controllers.Patch(c,"mongo") +// +// '200': +// description: 'Updated. A response body will be returned with +// a meaningful message.' +// '400': +// description: Bad request. An error message will be returned. +// '404': +// description: Not Found. An error message will be returned. +func PartialUpdateObject(c *gin.Context) { + controllers.Patch(c, "objects") } // swagger:operation PUT /{objs}/{IdOrHierarchyName} Objects UpdateObject @@ -247,8 +269,10 @@ func PartialUpdateObject(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: entity // in: path @@ -268,15 +292,16 @@ func PartialUpdateObject(c *gin.Context){ // default: "siteA" // // responses: -// '200': -// description: 'Updated. A response body will be returned with -// a meaningful message.' -// '400': -// description: Bad request. An error message will be returned. -// '404': -// description: Not Found. An error message will be returned. -func UpdateObject(c *gin.Context){ - controllers.Put(c,"mongo") +// +// '200': +// description: 'Updated. A response body will be returned with +// a meaningful message.' +// '400': +// description: Bad request. An error message will be returned. +// '404': +// description: Not Found. An error message will be returned. +func UpdateObject(c *gin.Context) { + controllers.Put(c, "objects") } // swagger:operation GET /{entity}? Objects GetEntityByQuery @@ -288,8 +313,10 @@ func UpdateObject(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: entity // in: path @@ -322,13 +349,14 @@ func UpdateObject(c *gin.Context){ // example: vendor=ibm ; name=siteA ; orientation=front // // responses: -// '204': -// description: 'Found. A response body will be returned with -// a meaningful message.' -// '404': -// description: Not found. An error message will be returned. -func GetEntityByQuery(c *gin.Context){ - controllers.Get(c,"mongo") +// +// '204': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: Not found. An error message will be returned. +func GetEntityByQuery(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation GET /tempunits/{IdOrHierarchyName} Objects GetTempUnit @@ -336,8 +364,10 @@ func GetEntityByQuery(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: IdOrHierarchyName // in: path @@ -346,14 +376,16 @@ func GetEntityByQuery(c *gin.Context){ // required: true // type: string // default: "siteA" +// // responses: -// '200': -// description: 'Found. A response body will be returned with -// a meaningful message.' -// '404': -// description: 'Nothing Found. An error message will be returned.' -func GetTempUnit(c *gin.Context){ - controllers.Get(c,"mongo") +// +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: 'Nothing Found. An error message will be returned.' +func GetTempUnit(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation GET /{entity}/{id}/{subent} Objects GetEntitiesOfAncestor @@ -364,36 +396,40 @@ func GetTempUnit(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: -// - name: entity -// in: query -// description: 'Indicates the entity. Only values of "sites", -// "buildings", "rooms" are acceptable' -// required: true -// type: string -// default: "sites" -// - name: ID -// in: query -// description: ID of object -// required: true -// type: int -// default: 999 -// - name: subent -// in: query -// description: Objects which 2 are levels lower in the hierarchy. -// required: true -// type: string -// default: buildings +// - name: entity +// in: query +// description: 'Indicates the entity. Only values of "sites", +// "buildings", "rooms" are acceptable' +// required: true +// type: string +// default: "sites" +// - name: ID +// in: query +// description: ID of object +// required: true +// type: int +// default: 999 +// - name: subent +// in: query +// description: Objects which 2 are levels lower in the hierarchy. +// required: true +// type: string +// default: buildings +// // responses: -// '200': -// description: 'Found. A response body will be returned with -// a meaningful message.' -// '404': -// description: Nothing Found. An error message will be returned. -func GetEntitiesOfAncestor(c *gin.Context){ - controllers.Get(c,"mongo") +// +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: Nothing Found. An error message will be returned. +func GetEntitiesOfAncestor(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation GET /{entity}/{IdOrHierarchyName}/all Objects GetEntityHierarchy @@ -402,53 +438,57 @@ func GetEntitiesOfAncestor(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: -// - name: entity -// in: path -// description: 'Entity (same as category) of the object. Accepted values: sites, domains, -// buildings, rooms, racks, devices, acs, panels, -// cabinets, groups, corridors, -// room-templates, obj-templates, bldg-templates, stray-devices.' -// required: true -// type: string -// default: "sites" -// - name: IdOrHierarchyName -// in: path -// description: 'ID or hierarchy name of desired object. -// For templates the slug is the ID.' -// required: true -// type: string -// default: "siteA" -// - name: limit -// in: query -// description: 'Limits the level of hierarchy for retrieval. if not -// specified for devices then the default value is maximum. -// Example: /api/devices/{id}/all?limit=2' -// required: false -// type: string -// default: 1 -// - name: fieldOnly -// in: query -// description: 'specify which object field to show in response. -// Multiple fieldOnly can be added. An invalid field is simply ignored.' -// - name: startDate -// in: query -// description: 'filter objects by lastUpdated >= startDate. -// Format: yyyy-mm-dd' -// - name: endDate -// in: query -// description: 'filter objects by lastUpdated <= endDate. -// Format: yyyy-mm-dd' +// - name: entity +// in: path +// description: 'Entity (same as category) of the object. Accepted values: sites, domains, +// buildings, rooms, racks, devices, acs, panels, +// cabinets, groups, corridors, +// room-templates, obj-templates, bldg-templates, stray-devices.' +// required: true +// type: string +// default: "sites" +// - name: IdOrHierarchyName +// in: path +// description: 'ID or hierarchy name of desired object. +// For templates the slug is the ID.' +// required: true +// type: string +// default: "siteA" +// - name: limit +// in: query +// description: 'Limits the level of hierarchy for retrieval. if not +// specified for devices then the default value is maximum. +// Example: /api/devices/{id}/all?limit=2' +// required: false +// type: string +// default: 1 +// - name: fieldOnly +// in: query +// description: 'specify which object field to show in response. +// Multiple fieldOnly can be added. An invalid field is simply ignored.' +// - name: startDate +// in: query +// description: 'filter objects by lastUpdated >= startDate. +// Format: yyyy-mm-dd' +// - name: endDate +// in: query +// description: 'filter objects by lastUpdated <= endDate. +// Format: yyyy-mm-dd' +// // responses: -// '200': -// description: 'Found. A response body will be returned with -// a meaningful message.' -// '404': -// description: Nothing Found. An error message will be returned. -func GetEntityHierarchy(c *gin.Context){ - controllers.Get(c,"mongo") +// +// '200': +// description: 'Found. A response body will be returned with +// a meaningful message.' +// '404': +// description: Nothing Found. An error message will be returned. +func GetEntityHierarchy(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation GET /hierarchy Objects GetCompleteHierarchy @@ -467,8 +507,8 @@ func GetEntityHierarchy(c *gin.Context){ // '500': // description: Server error. -func GetCompleteHierarchy(c *gin.Context){ - controllers.Get(c,"mongo") +func GetCompleteHierarchy(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation GET /hierarchy/attributes Objects GetCompleteHierarchyAttrs @@ -478,15 +518,18 @@ func GetCompleteHierarchy(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // responses: -// '200': -// description: 'Request is valid.' -// '500': -// description: Server error. -func GetCompleteHierarchyAttrs(c *gin.Context){ - controllers.Get(c,"mongo") +// +// '200': +// description: 'Request is valid.' +// '500': +// description: Server error. +func GetCompleteHierarchyAttrs(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation GET /{firstEntity}/{id}/{HierarchalPath} Objects GetEntitiesUsingNamesOfParents @@ -547,8 +590,8 @@ func GetCompleteHierarchyAttrs(c *gin.Context){ // '404': // description: Not Found. An error message will be returned. -func GetEntitiesUsingNamesOfParents(c *gin.Context){ - controllers.Get(c,"mongo") +func GetEntitiesUsingNamesOfParents(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation POST /validate/{entity} Objects ValidateObject @@ -556,8 +599,10 @@ func GetEntitiesUsingNamesOfParents(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: entity // in: path @@ -572,15 +617,17 @@ func GetEntitiesUsingNamesOfParents(c *gin.Context){ // in: body // required: true // default: {} +// // responses: -// '200': -// description: 'Createable. A response body will be returned with -// a meaningful message.' -// '400': -// description: 'Bad request. A response body with an error -// message will be returned.' -// '404': -// description: Not Found. An error message will be returned. -func ValidateObject(c *gin.Context){ - controllers.Post(c,"mongo") -} \ No newline at end of file +// +// '200': +// description: 'Createable. A response body will be returned with +// a meaningful message.' +// '400': +// description: 'Bad request. A response body with an error +// message will be returned.' +// '404': +// description: Not Found. An error message will be returned. +func ValidateObject(c *gin.Context) { + controllers.Post(c, "objects") +} diff --git a/BFF/handlers/organization.go b/BFF/handlers/organization.go index 99a913b3b..661616455 100644 --- a/BFF/handlers/organization.go +++ b/BFF/handlers/organization.go @@ -2,7 +2,7 @@ package handlers import ( "ogree-bff/controllers" - + "github.com/gin-gonic/gin" ) @@ -13,8 +13,10 @@ import ( // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: body // in: body @@ -26,22 +28,25 @@ import ( // example: '{"name": "John Doe", "roles": {"*": "manager"}, "email": "user@test.com", "password": "secret123"}' // // responses: -// '201': -// description: New account created -// '400': -// description: Bad request -// '403': -// description: User not authorised to create an account -// '500': -// description: Internal server error -func CreateAccount(c *gin.Context){ - controllers.Post(c,"mongo") +// +// '201': +// description: New account created +// '400': +// description: Bad request +// '403': +// description: User not authorised to create an account +// '500': +// description: Internal server error +func CreateAccount(c *gin.Context) { + controllers.Post(c, "objects") } + // swagger:operation POST /users/bulk Organization CreateBulk // Create multiples users with one request. // --- // security: // - Bearer: [] +// // produces: // - application/json // parameters: @@ -54,14 +59,15 @@ func CreateAccount(c *gin.Context){ // example: '[{"name": "John Doe", "roles": {"*": "manager"}, "email": "user@test.com"}]' // // responses: -// '200': -// description: Request processed, check response body for results -// '400': -// description: Bad request -// '500': -// description: Internal server error -func CreateBulk(c *gin.Context){ - controllers.Post(c,"mongo") +// +// '200': +// description: Request processed, check response body for results +// '400': +// description: Bad request +// '500': +// description: Internal server error +func CreateBulk(c *gin.Context) { + controllers.Post(c, "objects") } // swagger:operation GET /users Organization GetAllAccounts @@ -69,15 +75,17 @@ func CreateBulk(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: // - application/json // responses: -// '200': -// description: Return all possible users -// '500': -// description: Internal server error -func GetAllAccounts(c *gin.Context){ - controllers.Get(c,"mongo") +// +// '200': +// description: Return all possible users +// '500': +// description: Internal server error +func GetAllAccounts(c *gin.Context) { + controllers.Get(c, "objects") } // swagger:operation DELETE /users/{userid} Organization RemoveAccount @@ -85,26 +93,29 @@ func GetAllAccounts(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: // - application/json // parameters: -// - name: userid -// in: path -// description: 'The ID of the user to delete' -// required: true -// type: string -// example: "someUserId" +// - name: userid +// in: path +// description: 'The ID of the user to delete' +// required: true +// type: string +// example: "someUserId" +// // responses: -// '200': -// description: User removed -// '400': -// description: User ID not valid or not found -// '403': -// description: Caller not authorised to delete this user -// '500': -// description: Internal server error -func RemoveAccount(c *gin.Context){ - controllers.Delete(c,"mongo") +// +// '200': +// description: User removed +// '400': +// description: User ID not valid or not found +// '403': +// description: Caller not authorised to delete this user +// '500': +// description: Internal server error +func RemoveAccount(c *gin.Context) { + controllers.Delete(c, "objects") } // swagger:operation PATCH /users/{userid} Organization ModifyUserRoles @@ -112,8 +123,10 @@ func RemoveAccount(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: userid // in: path @@ -129,16 +142,17 @@ func RemoveAccount(c *gin.Context){ // example: '{"roles": {"*": "manager"}}' // // responses: -// '200': -// description: User roles modified -// '400': -// description: Bad request -// '403': -// description: Caller not authorised to modify this user -// '500': -// description: Internal server error -func ModifyUserRoles(c *gin.Context){ - controllers.Patch(c,"mongo") +// +// '200': +// description: User roles modified +// '400': +// description: Bad request +// '403': +// description: Caller not authorised to modify this user +// '500': +// description: Internal server error +func ModifyUserRoles(c *gin.Context) { + controllers.Patch(c, "objects") } // swagger:operation POST /domains/bulk Organization CreateBulkDomain @@ -147,21 +161,25 @@ func ModifyUserRoles(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // parameters: // - name: body // in: body // required: true // default: [{}] +// // responses: -// '200': -// description: 'Request processed. Check the response body -// for individual results for each of the sent domains' -// '400': -// description: 'Bad format: body is not a valid list of domains.' -func CreateBulkDomain(c *gin.Context){ - controllers.Post(c,"mongo") +// +// '200': +// description: 'Request processed. Check the response body +// for individual results for each of the sent domains' +// '400': +// description: 'Bad format: body is not a valid list of domains.' +func CreateBulkDomain(c *gin.Context) { + controllers.Post(c, "objects") } // swagger:operation GET /hierarchy/domains Organization GetCompleteDomainHierarchy @@ -171,13 +189,16 @@ func CreateBulkDomain(c *gin.Context){ // --- // security: // - Bearer: [] +// // produces: -// - application/json +// - application/json +// // responses: -// '200': -// description: 'Request is valid.' -// '500': -// description: Server error. -func GetCompleteDomainHierarchy(c *gin.Context){ - controllers.Get(c,"mongo") -} \ No newline at end of file +// +// '200': +// description: 'Request is valid.' +// '500': +// description: Server error. +func GetCompleteDomainHierarchy(c *gin.Context) { + controllers.Get(c, "objects") +} diff --git a/BFF/main.go b/BFF/main.go index f080a7010..29a018fb2 100644 --- a/BFF/main.go +++ b/BFF/main.go @@ -40,8 +40,8 @@ func main() { arangoAPI := os.Getenv("ARANGO_API") mongoAPI := os.Getenv("MONGO_API") apiList := []models.API { - {Name: "arango", URL: arangoAPI}, - {Name: "mongo", URL: mongoAPI}, + {Name: "devices", URL: arangoAPI}, + {Name: "objects", URL: mongoAPI}, } fmt.Println(apiList) router := services.InitRouter(apiList,env) diff --git a/BFF/services/router.go b/BFF/services/router.go index 370c0f320..f7c8a0b9e 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -48,7 +48,7 @@ func initDevices(protected, unprotected *gin.RouterGroup){ protected.POST("/Connections",handlers.CreateConnections) protected.DELETE("/Connections/:id",handlers.DeleteConnections) - protected.GET("/devices/:obj/objAttr/:objAttr/deviceAttr/:deviceAttr",handlers.GetDeviceBindingObject) + protected.GET("/devices/:entity/:obj/:objAttr/:deviceAttr",handlers.GetDeviceBindingObject) } func initAuth(protected, unprotected *gin.RouterGroup){ diff --git a/BFF/swagger.json b/BFF/swagger.json index 4a0527563..82ccab2d9 100644 --- a/BFF/swagger.json +++ b/BFF/swagger.json @@ -353,7 +353,7 @@ } } }, - "/devices/{obj}/objAttr/{objAttr}/deviceAttr/{deviceAttr}": { + "/devices/{entity}/{obj}/{objAttr}/{deviceAttr}": { "get": { "security": [ { diff --git a/CLI/controllers/commandController.go b/CLI/controllers/commandController.go index 9bb1af426..5e0843d95 100755 --- a/CLI/controllers/commandController.go +++ b/CLI/controllers/commandController.go @@ -195,7 +195,7 @@ func GetDevicesInfo(path string,filters string) (map[string]any, error) { func DevicesUrl(path,objAttr,devAttr,filters string) (string, error){ query := GenerateDeviceQuery(filters) device := strings.Split(strings.Split(filters, ".")[0],"%")[0] - return "/api/"+device+"/"+path+"/objAttr/"+objAttr+"/deviceAttr/"+devAttr+query,nil + return "/api/devices/"+device+"/"+path+"/"+objAttr+"/"+devAttr+query,nil } func GenerateDeviceQuery(filters string) (string) { From cc9493abb98e44f57847337453ab1b13855b37c2 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Thu, 10 Aug 2023 10:21:51 +0200 Subject: [PATCH 21/35] feat(bff): update devices routes --- BFF/controllers/devices.go | 42 +++ BFF/controllers/sender.go | 6 +- BFF/handlers/about.go | 14 +- BFF/handlers/auth.go | 50 ++-- BFF/handlers/devices.go | 214 +++++++++------ BFF/services/router.go | 8 +- BFF/swagger.json | 376 +++++++-------------------- CLI/controllers/commandController.go | 6 +- 8 files changed, 305 insertions(+), 411 deletions(-) diff --git a/BFF/controllers/devices.go b/BFF/controllers/devices.go index 22439156b..d91743e8b 100644 --- a/BFF/controllers/devices.go +++ b/BFF/controllers/devices.go @@ -1,6 +1,7 @@ package controllers import ( + "fmt" "net/http" "ogree-bff/utils/token" @@ -84,3 +85,44 @@ func DeviceBindingObject(c *gin.Context) { return } + + +func GetDevice(c *gin.Context,url,methode string){ + + key := token.ExtractToken(c) + query := GetQueryString(c) + fmt.Println(c.Request.URL.Query(),query) + deviceResp, err := Send(methode, url, query, key, nil) + if err != nil { + if deviceResp != nil { + result := GetJSONBody(deviceResp) + c.IndentedJSON(deviceResp.StatusCode, result.Message) + return + } + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + result := GetJSONBody(deviceResp) + c.IndentedJSON(deviceResp.StatusCode, result.Message) + return +} + +func PostDevice(c *gin.Context,url, method string){ + + var data interface{} + // Call BindJSON to bind the received JSON to + if err := c.ShouldBindJSON(&data); err != nil { + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + + key := token.ExtractToken(c) + resp,err := Send(method,url,"",key,data) + fmt.Println(err) + if err != nil && resp == nil{ + c.IndentedJSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) + return + } + result := GetJSONBody(resp) + c.IndentedJSON(resp.StatusCode, result.Message) +} diff --git a/BFF/controllers/sender.go b/BFF/controllers/sender.go index 183573e5a..235cb1da9 100644 --- a/BFF/controllers/sender.go +++ b/BFF/controllers/sender.go @@ -8,7 +8,7 @@ import ( "net/http" "ogree-bff/models" "ogree-bff/utils/token" - + "net/url" "github.com/gin-gonic/gin" ) @@ -16,9 +16,9 @@ func GetQueryString(c *gin.Context) (string) { query := "" for key,value := range c.Request.URL.Query() { if query == ""{ - query+="?"+key+"="+value[0] + query+="?"+key+"="+url.QueryEscape(value[0]) }else{ - query+="&"+key+"="+value[0] + query+="&"+key+"="+url.QueryEscape(value[0]) } } return query diff --git a/BFF/handlers/about.go b/BFF/handlers/about.go index 23ba9140e..5dd9a5a6d 100644 --- a/BFF/handlers/about.go +++ b/BFF/handlers/about.go @@ -17,10 +17,10 @@ import ( // // responses: // -// '200': -// description: 'Request is valid.' -// '504': -// description: Server error. +// '200': +// description: 'Request is valid.' +// '504': +// description: Server error. func GetStats(c *gin.Context) { controllers.Get(c, "objects") } @@ -36,9 +36,9 @@ func GetStats(c *gin.Context) { // // responses: // -// '200': -// description: 'OK. A response body will be returned with -// version details.' +// '200': +// description: 'OK. A response body will be returned with +// version details.' func GetAPIVersion(c *gin.Context) { controllers.Get(c, "objects") } diff --git a/BFF/handlers/auth.go b/BFF/handlers/auth.go index 90845fa51..c33786609 100644 --- a/BFF/handlers/auth.go +++ b/BFF/handlers/auth.go @@ -22,13 +22,12 @@ import ( // example: '{"email": "user@test.com", "password": "secret123"}' // // responses: -// -// '200': -// description: Authenticated -// '400': -// description: Bad request -// '500': -// description: Internal server error +// '200': +// description: Authenticated +// '400': +// description: Bad request +// '500': +// description: Internal server error func Login(c *gin.Context) { controllers.Post(c, "objects") } @@ -43,13 +42,12 @@ func Login(c *gin.Context) { // - application/json // // responses: -// -// '200': -// description: Token is valid. -// '403': -// description: Unauthorized -// '500': -// description: Internal server error +// '200': +// description: Token is valid. +// '403': +// description: Unauthorized +// '500': +// description: Internal server error func ValidToken(c *gin.Context) { controllers.Get(c, "objects") @@ -74,12 +72,12 @@ func ValidToken(c *gin.Context) { // // responses: // -// '200': -// description: Password changed -// '400': -// description: Bad request -// '500': -// description: Internal server error +// '200': +// description: Password changed +// '400': +// description: Bad request +// '500': +// description: Internal server error func ModifyUserPassword(c *gin.Context) { controllers.Post(c, "objects") } @@ -105,11 +103,11 @@ func ModifyUserPassword(c *gin.Context) { // // responses: // -// '200': +// '200': // description: Password changed -// '400': +// '400': // description: Bad request -// '500': +// '500': // description: Internal server error func ResetUserPassword(c *gin.Context) { controllers.Post(c, "objects") @@ -133,11 +131,11 @@ func ResetUserPassword(c *gin.Context) { // // responses: // -// '200': +// '200': // description: request processed. If account exists, an email with a reset token is sent -// '400': +// '400': // description: Bad request -// '500': +// '500': // description: Internal server error func UserForgotPassword(c *gin.Context) { controllers.Post(c, "objects") diff --git a/BFF/handlers/devices.go b/BFF/handlers/devices.go index cad60b5c3..8a0cb8991 100644 --- a/BFF/handlers/devices.go +++ b/BFF/handlers/devices.go @@ -2,11 +2,11 @@ package handlers import ( "ogree-bff/controllers" - + "net/http" "github.com/gin-gonic/gin" ) -// swagger:operation GET /devices Devices Devices +// swagger:operation GET /devices/{entity} Devices Devices // Get Devices list // // --- @@ -16,6 +16,11 @@ import ( // description: Key of device // required: false // type: string +// - name: entity +// in: path +// description: database to retrieve devices +// required: true +// type: string // - name: _name // in: query // description: Name of device @@ -46,14 +51,26 @@ import ( // "$ref": "#/definitions/ErrorResponse" func GetDevices(c *gin.Context) { - controllers.Get(c, "devices") + entity := c.Param("entity") + + deviceURL, ok := c.Value(entity).(string) + if !ok { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": entity + " has not database"}) + return + } + controllers.GetDevice(c, deviceURL+"/api/devices","GET") } -// swagger:operation GET /devices/ConnecteTo/{device} Devices GetDevicesConnectedTo +// swagger:operation GET /devices/{entity}/ConnecteTo/{device} Devices GetDevicesConnectedTo // Get Devices connected to a device // // --- // parameters: +// - name: entity +// in: path +// description: database to retrieve devices +// required: true +// type: string // - name: device // in: path // description: Key of device @@ -84,22 +101,29 @@ func GetDevices(c *gin.Context) { // - Bearer: [] // // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func GetDevicesConnectedTo(c *gin.Context) { - controllers.Get(c, "devices") + + entity := c.Param("entity") + id := c.Param("id") + deviceURL, ok := c.Value(entity).(string) + if !ok { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": entity + " has not database"}) + return + } + controllers.GetDevice(c, deviceURL+"/api/devices/ConnecteTo/"+id,"GET") } -// swagger:operation POST /devices Devices CreateDevices +// swagger:operation POST /devices/{entity} Devices CreateDevices // Create new Devices // // --- @@ -107,6 +131,11 @@ func GetDevicesConnectedTo(c *gin.Context) { // - Bearer: [] // // parameters: +// - name: entity +// in: path +// description: database to retrieve devices +// required: true +// type: string // - name: body // in: body // description: 'Mandatory: _name, group_name,created.' @@ -115,26 +144,37 @@ func GetDevicesConnectedTo(c *gin.Context) { // example: '{"_name": "server", "group_name": "exwipen22","created": "2022-07-18"}' // // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func CreateDevices(c *gin.Context) { - controllers.Post(c, "devices") + entity := c.Param("entity") + + deviceURL, ok := c.Value(entity).(string) + if !ok { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": entity + " has not database"}) + return + } + controllers.PostDevice(c, deviceURL+"/api/devices","POST") } -// swagger:operation DELETE /devices/{device} Devices DeleteDevices +// swagger:operation DELETE /devices/{entity}{device} Devices DeleteDevices // Delete Devices by key // // --- // parameters: +// - name: entity +// in: path +// description: database to retrieve devices +// required: true +// type: string // - name: device // in: path // description: device looking for @@ -145,19 +185,25 @@ func CreateDevices(c *gin.Context) { // - Bearer: [] // // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func DeleteDevice(c *gin.Context) { - controllers.Delete(c, "devices") + entity := c.Param("entity") + id := c.Param("id") + deviceURL, ok := c.Value(entity).(string) + if !ok { + c.IndentedJSON(http.StatusBadRequest, gin.H{"message": entity + " has not database"}) + return + } + controllers.GetDevice(c, deviceURL+"/api/devices/"+id,"DELETE") } // swagger:operation GET /Connections Devices GetConnections @@ -185,17 +231,16 @@ func DeleteDevice(c *gin.Context) { // - Bearer: [] // // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func GetConnections(c *gin.Context) { controllers.Get(c, "devices") } @@ -216,17 +261,16 @@ func GetConnections(c *gin.Context) { // example: '{"_from": "devices/123", "_to": "devices/111"}' // // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func CreateConnections(c *gin.Context) { controllers.Post(c, "devices") } @@ -246,17 +290,16 @@ func CreateConnections(c *gin.Context) { // type: string // // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func DeleteConnections(c *gin.Context) { controllers.Delete(c, "devices") } @@ -306,17 +349,16 @@ func DeleteConnections(c *gin.Context) { // - Bearer: [] // // responses: -// -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func GetDeviceBindingObject(c *gin.Context) { controllers.DeviceBindingObject(c) diff --git a/BFF/services/router.go b/BFF/services/router.go index f7c8a0b9e..01e1d4a5d 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -39,10 +39,10 @@ func APIMiddleware(apiList []models.API) gin.HandlerFunc { } func initDevices(protected, unprotected *gin.RouterGroup){ - protected.GET("/devices",handlers.GetDevices) - protected.GET("/devices/ConnecteTo/:key",handlers.GetDevicesConnectedTo) - protected.POST("/devices",handlers.CreateDevices) - protected.DELETE("/devices/:id",handlers.DeleteDevice) + protected.GET("/devices/:entity",handlers.GetDevices) + protected.GET("/devices/:entity/ConnecteTo/:id",handlers.GetDevicesConnectedTo) + protected.POST("/devices/:entity",handlers.CreateDevices) + protected.DELETE("/devices/:entity/:id",handlers.DeleteDevice) protected.GET("/Connections",handlers.GetConnections) protected.POST("/Connections",handlers.CreateConnections) diff --git a/BFF/swagger.json b/BFF/swagger.json index 82ccab2d9..d47024c89 100644 --- a/BFF/swagger.json +++ b/BFF/swagger.json @@ -149,7 +149,7 @@ } } }, - "/devices": { + "/devices/{entity}": { "get": { "security": [ { @@ -168,6 +168,13 @@ "name": "_key", "in": "query" }, + { + "type": "string", + "description": "database to retrieve devices", + "name": "entity", + "in": "path", + "required": true + }, { "type": "string", "description": "Name of device", @@ -218,6 +225,13 @@ ], "operationId": "CreateDevices", "parameters": [ + { + "type": "string", + "description": "database to retrieve devices", + "name": "entity", + "in": "path", + "required": true + }, { "format": "object", "example": "{\"_name\": \"server\", \"group_name\": \"exwipen22\",\"created\": \"2022-07-18\"}", @@ -247,7 +261,7 @@ } } }, - "/devices/ConnecteTo/{device}": { + "/devices/{entity}/ConnecteTo/{device}": { "get": { "security": [ { @@ -260,6 +274,13 @@ ], "operationId": "GetDevicesConnectedTo", "parameters": [ + { + "type": "string", + "description": "database to retrieve devices", + "name": "entity", + "in": "path", + "required": true + }, { "type": "string", "description": "Key of device", @@ -312,47 +333,6 @@ } } }, - "/devices/{device}": { - "delete": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Delete Devices by key", - "tags": [ - "Devices" - ], - "operationId": "DeleteDevices", - "parameters": [ - { - "type": "string", - "description": "device looking for", - "name": "device", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "successful", - "schema": { - "items": { - "$ref": "#/definitions/SuccessResponse" - } - } - }, - "500": { - "description": "Error", - "schema": { - "items": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - } - } - }, "/devices/{entity}/{obj}/{objAttr}/{deviceAttr}": { "get": { "security": [ @@ -432,6 +412,54 @@ } } }, + "/devices/{entity}{device}": { + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Delete Devices by key", + "tags": [ + "Devices" + ], + "operationId": "DeleteDevices", + "parameters": [ + { + "type": "string", + "description": "database to retrieve devices", + "name": "entity", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "device looking for", + "name": "device", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "successful", + "schema": { + "items": { + "$ref": "#/definitions/SuccessResponse" + } + } + }, + "500": { + "description": "Error", + "schema": { + "items": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, "/domains/bulk": { "post": { "security": [ @@ -457,15 +485,7 @@ "in": "body", "required": true } - ], - "responses": { - "200": { - "description": "Request processed. Check the response body for individual results for each of the sent domains" - }, - "400": { - "description": "Bad format: body is not a valid list of domains." - } - } + ] } }, "/hierarchy": { @@ -509,15 +529,7 @@ "Objects" ], "summary": "Returns attributes of all objects.", - "operationId": "GetCompleteHierarchyAttrs", - "responses": { - "200": { - "description": "Request is valid." - }, - "500": { - "description": "Server error." - } - } + "operationId": "GetCompleteHierarchyAttrs" } }, "/hierarchy/domains": { @@ -535,15 +547,7 @@ "Organization" ], "summary": "Returns domain complete hierarchy.", - "operationId": "GetCompleteDomainHierarchy", - "responses": { - "200": { - "description": "Request is valid." - }, - "500": { - "description": "Server error." - } - } + "operationId": "GetCompleteDomainHierarchy" } }, "/login": { @@ -688,18 +692,7 @@ "in": "body", "required": true } - ], - "responses": { - "200": { - "description": "Project successfully created." - }, - "400": { - "description": "Bad Request. Invalid project format." - }, - "500": { - "description": "Internal server error." - } - } + ] } }, "/projects/{ProjectID}": { @@ -734,18 +727,7 @@ "in": "body", "required": true } - ], - "responses": { - "200": { - "description": "Project successfully updated." - }, - "400": { - "description": "Bad Request. Invalid project format." - }, - "500": { - "description": "Internal server error" - } - } + ] }, "delete": { "security": [ @@ -770,18 +752,7 @@ "in": "path", "required": true } - ], - "responses": { - "200": { - "description": "Project successfully updated." - }, - "404": { - "description": "Not Found. Invalid project ID." - }, - "500": { - "description": "Internal server error" - } - } + ] } }, "/stats": { @@ -833,15 +804,7 @@ "in": "path", "required": true } - ], - "responses": { - "200": { - "description": "Found. A response body will be returned with a meaningful message." - }, - "404": { - "description": "Nothing Found. An error message will be returned." - } - } + ] } }, "/token/valid": { @@ -886,15 +849,7 @@ "Organization" ], "summary": "Get a list of users that the caller is allowed to see.", - "operationId": "GetAllAccounts", - "responses": { - "200": { - "description": "Return all possible users" - }, - "500": { - "description": "Internal server error" - } - } + "operationId": "GetAllAccounts" }, "post": { "security": [ @@ -920,21 +875,7 @@ "in": "body", "required": true } - ], - "responses": { - "201": { - "description": "New account created" - }, - "400": { - "description": "Bad request" - }, - "403": { - "description": "User not authorised to create an account" - }, - "500": { - "description": "Internal server error" - } - } + ] } }, "/users/bulk": { @@ -961,18 +902,7 @@ "in": "body", "required": true } - ], - "responses": { - "200": { - "description": "Request processed, check response body for results" - }, - "400": { - "description": "Bad request" - }, - "500": { - "description": "Internal server error" - } - } + ] } }, "/users/password/change": { @@ -1110,21 +1040,7 @@ "in": "path", "required": true } - ], - "responses": { - "200": { - "description": "User removed" - }, - "400": { - "description": "User ID not valid or not found" - }, - "403": { - "description": "Caller not authorised to delete this user" - }, - "500": { - "description": "Internal server error" - } - } + ] }, "patch": { "security": [ @@ -1157,21 +1073,7 @@ "in": "body", "required": true } - ], - "responses": { - "200": { - "description": "User roles modified" - }, - "400": { - "description": "Bad request" - }, - "403": { - "description": "Caller not authorised to modify this user" - }, - "500": { - "description": "Internal server error" - } - } + ] } }, "/validate/{entity}": { @@ -1204,18 +1106,7 @@ "in": "body", "required": true } - ], - "responses": { - "200": { - "description": "Createable. A response body will be returned with a meaningful message." - }, - "400": { - "description": "Bad request. A response body with an error message will be returned." - }, - "404": { - "description": "Not Found. An error message will be returned." - } - } + ] } }, "/version": { @@ -1280,15 +1171,7 @@ "name": "endDate", "in": "query" } - ], - "responses": { - "200": { - "description": "Found. A response body will be returned with a meaningful message." - }, - "404": { - "description": "Nothing Found. An error message will be returned." - } - } + ] }, "post": { "security": [ @@ -1319,15 +1202,7 @@ "in": "body", "required": true } - ], - "responses": { - "201": { - "description": "Created. A response body will be returned with a meaningful message." - }, - "400": { - "description": "Bad request. A response body with an error message will be returned." - } - } + ] } }, "/{entity}/{IdOrHierarchyName}": { @@ -1378,18 +1253,7 @@ "name": "endDate", "in": "query" } - ], - "responses": { - "200": { - "description": "Found. A response body will be returned with a meaningful message." - }, - "400": { - "description": "Bad request. An error message will be returned." - }, - "404": { - "description": "Not Found. An error message will be returned." - } - } + ] }, "delete": { "security": [ @@ -1422,15 +1286,7 @@ "in": "path", "required": true } - ], - "responses": { - "204": { - "description": "Successfully deleted object. No response body will be returned" - }, - "404": { - "description": "Not found. An error message will be returned" - } - } + ] }, "patch": { "security": [ @@ -1464,18 +1320,7 @@ "in": "path", "required": true } - ], - "responses": { - "200": { - "description": "Updated. A response body will be returned with a meaningful message." - }, - "400": { - "description": "Bad request. An error message will be returned." - }, - "404": { - "description": "Not Found. An error message will be returned." - } - } + ] } }, "/{entity}/{IdOrHierarchyName}/all": { @@ -1533,15 +1378,7 @@ "name": "endDate", "in": "query" } - ], - "responses": { - "200": { - "description": "Found. A response body will be returned with a meaningful message." - }, - "404": { - "description": "Nothing Found. An error message will be returned." - } - } + ] } }, "/{entity}/{id}/{subent}": { @@ -1585,15 +1422,7 @@ "in": "query", "required": true } - ], - "responses": { - "200": { - "description": "Found. A response body will be returned with a meaningful message." - }, - "404": { - "description": "Nothing Found. An error message will be returned." - } - } + ] } }, "/{entity}?": { @@ -1644,15 +1473,7 @@ "name": "attributes", "in": "query" } - ], - "responses": { - "204": { - "description": "Found. A response body will be returned with a meaningful message." - }, - "404": { - "description": "Not found. An error message will be returned." - } - } + ] } }, "/{firstEntity}/{id}/{HierarchalPath}": { @@ -1741,18 +1562,7 @@ "in": "path", "required": true } - ], - "responses": { - "200": { - "description": "Updated. A response body will be returned with a meaningful message." - }, - "400": { - "description": "Bad request. An error message will be returned." - }, - "404": { - "description": "Not Found. An error message will be returned." - } - } + ] } } }, diff --git a/CLI/controllers/commandController.go b/CLI/controllers/commandController.go index 5e0843d95..56167bc33 100755 --- a/CLI/controllers/commandController.go +++ b/CLI/controllers/commandController.go @@ -10,6 +10,7 @@ import ( "log" "math/rand" "net/http" + "net/url" "os" "os/exec" pathutil "path" @@ -203,10 +204,11 @@ func GenerateDeviceQuery(filters string) (string) { result:="" for _,query := range queries { if strings.Contains(query,"="){ + q := strings.Split(query,"=") if result == "" { - result+= "?"+query + result+= "?"+q[0]+"="+url.QueryEscape(q[1]) }else{ - result+="&"+query + result+="&"+q[0]+"="+url.QueryEscape(q[1]) } } } From ac831f6108679225542af377c51769713f35d369 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Thu, 10 Aug 2023 10:22:15 +0200 Subject: [PATCH 22/35] readme(ARANGO): add readme for arango api --- ARANGO_API/readme.md | 120 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 ARANGO_API/readme.md diff --git a/ARANGO_API/readme.md b/ARANGO_API/readme.md new file mode 100644 index 000000000..7bf1efb5c --- /dev/null +++ b/ARANGO_API/readme.md @@ -0,0 +1,120 @@ +# ArangoDB Database API in GoLang + +This GoLang API enables management of "devices" and "connections" elements within an ArangoDB database. It provides endpoints to perform CRUD (Create, Read, Update, Delete) operations on these elements. + + +## Configuration + +Before you begin, ensure you have an ArangoDB database up and running. Set the following environment variables in the API's configuration or as part of your runtime environment: + +- `ARANGO_URL`: The URL of your ArangoDB instance. +- `ARANGO_DATABASE`: The name of the ArangoDB database you'll be using. +- `ARANGO_USER`: The username for authentication. +- `ARANGO_PASSWORD`: The password for authentication. + + +For example, you can set these environment variables in a `.env` file in the root directory of your project: + +```env +ARANGO_URL=http://localhost:8529 +ARANGO_DATABASE=mydatabase +ARANGO_USER=user +ARANGO_PASSWORD=password +``` + +## Installation and Execution + +1. Clone this repository to your local machine. +2. Install any necessary dependencies if required. +3. Compile and run the API using the following command: + +```bash +go run main.go +``` +The server should start and be ready to accept requests. + +## Endpoints +### Devices + +- GET /devices : Retrieve the list of all devices. +- GET /devices/:id : Retrieve information about a specific device based on its ID. +- GET /devices/ConnectedTo/:id : Retrieve the list of all devices connected to a specific device +- POST /devices :Add a new device to the database. Data must be provided in the request body in JSON format. +- DELETE /devices/:id :Delete a specific device based on its ID. + + +Example JSON data for a new device: + +```json +{ + "_name": "storage_bay", + "category": "port", + "created": "2016-04-22", + "expired": "3000-01-01", + "group_name": "GS00OPSAN06", + "hba_device_name": "nsa.*", + "sp_name": "sp_b", + "sp_port_id": "0", + "storage_group_name": "storage" +} +``` + +### Connections + + +- GET /connections : Retrieve the list of all connections. +- POST /connections : Add a new connection to the database. Data must be provided in the request body in JSON format. +- DELETE /connections/:id : Delete a specific connection based on its ID. + + +Example JSON data for a new connection: + +```json + { + "_from": "devices/*", + "_to": "devices/*", + "created": "2016-04-22", + "expired": "3000-01-01", + "type": "parent of (between partens)" +} +``` + +### Responses +The API returns data in JSON format for all operations. Responses typically include a array containing the requested data or an error message in case of an issue. + +Example successful response: + +```json + +{ +[ +{ + "_name": "storage_bay", + "category": "port", + "created": "2016-04-22", + "expired": "3000-01-01", + "group_name": "GS00OPSAN06", + "hba_device_name": "nsa.*", + "sp_name": "sp_b", + "sp_port_id": "0", + "storage_group_name": "storage" +} +] +} +``` +Example error response: + +```json +{ + "message": "Error message" +} +``` + +## API Documentation +You can explore the API documentation using Swagger UI. After starting the server, navigate to /docs in your web browser to access the interactive documentation and explore the available endpoints, request and response schemas, and even test the API directly from the documentation. + +For example, if the API is running locally, you can access Swagger UI at: + +```bash +http://localhost:8080/docs +`````` \ No newline at end of file From 911be5a7f1ab4caad815400ea0a40b08a7c7dd32 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Thu, 10 Aug 2023 11:06:57 +0200 Subject: [PATCH 23/35] fix(bff): api info for bff has json file --- ARANGO_API/main.go | 4 ++-- ARANGO_API/readme.md | 2 ++ BFF/Dockerfile | 1 + BFF/api.json | 5 +++++ BFF/main.go | 32 +++++++++++++++++++++++--------- deploy/docker/bff_api_list.json | 5 +++++ deploy/docker/docker-compose.yml | 8 +++++--- 7 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 BFF/api.json create mode 100644 deploy/docker/bff_api_list.json diff --git a/ARANGO_API/main.go b/ARANGO_API/main.go index 39c8ae34b..51670fceb 100644 --- a/ARANGO_API/main.go +++ b/ARANGO_API/main.go @@ -40,7 +40,7 @@ func main() { bdd := os.Getenv("ARANGO_DATABASE") user := os.Getenv("ARANGO_USER") password := os.Getenv("ARANGO_PASSWORD") - + port := os.Getenv("API_PORT") db, err2 := database.ConnectToArango(addr,bdd, user, password) if err2 != nil { @@ -51,5 +51,5 @@ func main() { database.CreateCollection(db, "devices") router := services.InitRouter(db,addr) - router.Run(":8080") + router.Run(":"+port) } diff --git a/ARANGO_API/readme.md b/ARANGO_API/readme.md index 7bf1efb5c..7c2771336 100644 --- a/ARANGO_API/readme.md +++ b/ARANGO_API/readme.md @@ -11,6 +11,7 @@ Before you begin, ensure you have an ArangoDB database up and running. Set the f - `ARANGO_DATABASE`: The name of the ArangoDB database you'll be using. - `ARANGO_USER`: The username for authentication. - `ARANGO_PASSWORD`: The password for authentication. +- `ÀPI_PORT`: The port where API running For example, you can set these environment variables in a `.env` file in the root directory of your project: @@ -20,6 +21,7 @@ ARANGO_URL=http://localhost:8529 ARANGO_DATABASE=mydatabase ARANGO_USER=user ARANGO_PASSWORD=password +API_PORT="8081" ``` ## Installation and Execution diff --git a/BFF/Dockerfile b/BFF/Dockerfile index cabc13407..f69e6b18d 100644 --- a/BFF/Dockerfile +++ b/BFF/Dockerfile @@ -21,6 +21,7 @@ FROM alpine:3.16 WORKDIR /bin COPY --from=build /build/ogree-bff . +COPY --from=build /build/api.json . COPY --from=build /build/swagger.json . diff --git a/BFF/api.json b/BFF/api.json new file mode 100644 index 000000000..89be85aaa --- /dev/null +++ b/BFF/api.json @@ -0,0 +1,5 @@ +[ + {"name":"server", "url": "http://localhost:8080"}, + {"name":"bay", "url": "http://localhost:8081"}, + {"name":"objects", "url": "http://localhost:3001"} +] \ No newline at end of file diff --git a/BFF/main.go b/BFF/main.go index 29a018fb2..1e627abda 100644 --- a/BFF/main.go +++ b/BFF/main.go @@ -17,14 +17,33 @@ package main import ( - + "encoding/json" "fmt" - "os" - e "github.com/joho/godotenv" + "io/ioutil" "ogree-bff/models" "ogree-bff/services" + "os" + + e "github.com/joho/godotenv" ) + +func GetAPIInfo() ([]models.API) { + jsonFile, err := os.Open("api.json") + // if we os.Open returns an error then handle it + if err != nil { + fmt.Println(err) + } + fmt.Println("Successfully Opened users.json") + // defer the closing of our jsonFile so that we can parse it later on + defer jsonFile.Close() + byteValue, _ := ioutil.ReadAll(jsonFile) + var api []models.API + json.Unmarshal(byteValue, &api) + + return api +} + func main() { env := os.Getenv("ENV") @@ -37,12 +56,7 @@ func main() { } } BFF_PORT := os.Getenv("BFF_PORT") - arangoAPI := os.Getenv("ARANGO_API") - mongoAPI := os.Getenv("MONGO_API") - apiList := []models.API { - {Name: "devices", URL: arangoAPI}, - {Name: "objects", URL: mongoAPI}, - } + apiList := GetAPIInfo() fmt.Println(apiList) router := services.InitRouter(apiList,env) router.Run(":"+BFF_PORT) diff --git a/deploy/docker/bff_api_list.json b/deploy/docker/bff_api_list.json new file mode 100644 index 000000000..89be85aaa --- /dev/null +++ b/deploy/docker/bff_api_list.json @@ -0,0 +1,5 @@ +[ + {"name":"server", "url": "http://localhost:8080"}, + {"name":"bay", "url": "http://localhost:8081"}, + {"name":"objects", "url": "http://localhost:3001"} +] \ No newline at end of file diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index c5b83ed7b..d47c8b7dd 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -94,8 +94,9 @@ services: - ARANGO_USER=${ARANGO_USER} - ARANGO_PASSWORD=${ARANGO_PASS} - API_SECRET=${AUTH_SECRET} + - API_PORT=${ARANGO_API_PORT} ports: - - ${ARANGO_API_PORT}:8080 + - ${ARANGO_API_PORT}:${ARANGO_API_PORT} healthcheck: test: ["CMD", "curl","-f","http://${COMPOSE_PROJECT_NAME}_arango_db:5829/_api/version"] timeout: 30s @@ -111,13 +112,14 @@ services: container_name: ${COMPOSE_PROJECT_NAME}_bff environment: - ENV=production - - ARANGO_API=http://${COMPOSE_PROJECT_NAME}_arango_api:${ARANGO_API_PORT} - - MONGO_API=http://${COMPOSE_PROJECT_NAME}_api:${API_PORT} - BFF_PORT=${BFF_PORT} - BFF_SECRET=${AUTH_SECRET} + volumes: + - ./bff_api_list.json:/bin/api.json depends_on: - ogree_api - arango_api + network_mode: "host" ports: - ${BFF_PORT}:${BFF_PORT} From aebc1a4139420d80a9a82b5aef12e41d8c71cb03 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Thu, 10 Aug 2023 11:19:46 +0200 Subject: [PATCH 24/35] fix(bff): stop exposing api into docker compose --- deploy/docker/bff_api_list.json | 5 ++--- deploy/docker/docker-compose.yml | 7 +------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/deploy/docker/bff_api_list.json b/deploy/docker/bff_api_list.json index 89be85aaa..139d9e276 100644 --- a/deploy/docker/bff_api_list.json +++ b/deploy/docker/bff_api_list.json @@ -1,5 +1,4 @@ [ - {"name":"server", "url": "http://localhost:8080"}, - {"name":"bay", "url": "http://localhost:8081"}, - {"name":"objects", "url": "http://localhost:3001"} + {"name":"server", "url": "http://ogree-core_arango_api:8080"}, + {"name":"objects", "url": "http://ogree-core_api:3001"} ] \ No newline at end of file diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index d47c8b7dd..a633cbd9f 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -6,15 +6,13 @@ services: image: ogree/api:${IMAGE_TAG} container_name: ${COMPOSE_PROJECT_NAME}_api environment: - - api_port=3001 + - api_port=${API_PORT} - db_host=${COMPOSE_PROJECT_NAME}_db - db_port=27017 - db_user=${COMPOSE_PROJECT_NAME} - db_pass=${CUSTOMER_API_PASSWORD} - db=${COMPOSE_PROJECT_NAME} - token_password=${AUTH_SECRET} - ports: - - ${API_PORT}:3001 depends_on: - ogree_db restart: on-failure:10 @@ -95,8 +93,6 @@ services: - ARANGO_PASSWORD=${ARANGO_PASS} - API_SECRET=${AUTH_SECRET} - API_PORT=${ARANGO_API_PORT} - ports: - - ${ARANGO_API_PORT}:${ARANGO_API_PORT} healthcheck: test: ["CMD", "curl","-f","http://${COMPOSE_PROJECT_NAME}_arango_db:5829/_api/version"] timeout: 30s @@ -119,7 +115,6 @@ services: depends_on: - ogree_api - arango_api - network_mode: "host" ports: - ${BFF_PORT}:${BFF_PORT} From 02732a80ec40f0285b505f8fd20616307a137c0c Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Thu, 10 Aug 2023 14:43:48 +0200 Subject: [PATCH 25/35] fix(doc): add BFF readme.md --- ARANGO_API/readme.md | 4 ++-- BFF/readme.md | 50 ++++++++++++++++++++++++++++++++++++++++++++ CLI/other/man/get.md | 16 ++++++++++++-- 3 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 BFF/readme.md diff --git a/ARANGO_API/readme.md b/ARANGO_API/readme.md index 7c2771336..b087559ef 100644 --- a/ARANGO_API/readme.md +++ b/ARANGO_API/readme.md @@ -5,13 +5,13 @@ This GoLang API enables management of "devices" and "connections" elements withi ## Configuration -Before you begin, ensure you have an ArangoDB database up and running. Set the following environment variables in the API's configuration or as part of your runtime environment: +Before you begin, ensure you have an ArangoDB database up and running. Set the following environment variables in a .env file or as part of your runtime environment: - `ARANGO_URL`: The URL of your ArangoDB instance. - `ARANGO_DATABASE`: The name of the ArangoDB database you'll be using. - `ARANGO_USER`: The username for authentication. - `ARANGO_PASSWORD`: The password for authentication. -- `ÀPI_PORT`: The port where API running +- `ÀPI_PORT`: The port where API listenning For example, you can set these environment variables in a `.env` file in the root directory of your project: diff --git a/BFF/readme.md b/BFF/readme.md new file mode 100644 index 000000000..1715700c6 --- /dev/null +++ b/BFF/readme.md @@ -0,0 +1,50 @@ +# Ogree BFF (Back for Frontend) for API Routing and Aggregation + +This is the Ogree BFF (Back for Frontend) service that handles API redirection and aggregation, primarily designed to streamline frontend-backend communication. It acts as a gateway for routing requests to various backend APIs and provides a unified interface for frontend applications. + +## Configuration + +Before you begin, set the following environment variables in a .env file or as part of your runtime: + +- `ARANGO_PASSWORD`: The password for authentication. +- `BFF_PORT`: The port where BFF listenning + +You also need a api.json file, that contains an array of `name` and `url` of all API you when to use. + +Notice that this minimal configuration you need is an API 'objects': + +Exemple of api.json: + +```json +[ + {"name":"server", "url": "http://localhost:8080"}, + {"name":"objects", "url": "http://localhost:3001"} +] +``` +## Installation and Execution + +1. Clone this repository to your local machine. +2. Install any necessary dependencies if required. +3. Compile and run the BFF using the following command: + +```bash +go run main.go +``` +The server should start and be ready to accept requests. + +## Endpoints + +### Bindings Data between objects's API and another + +- GET /api/devices/:apiName/:objects/:objectAttributes/:devicesAttributes : Retrieve the list of all devices in the database connect to apiName where the specific attributes of the objects match the specific attributes of devices + + + +## API Documentation +You can explore the BFF documentation using Swagger UI. After starting the server, navigate to /docs in your web browser to access the interactive documentation and explore the available endpoints, request and response schemas, and even test the API directly from the documentation. + +For example, if the API is running locally, you can access Swagger UI at: + +```bash +http://localhost:/docs +`````` \ No newline at end of file diff --git a/CLI/other/man/get.md b/CLI/other/man/get.md index e7b865a08..ca6beb6d9 100644 --- a/CLI/other/man/get.md +++ b/CLI/other/man/get.md @@ -1,11 +1,23 @@ -USAGE: get [PATH](optional) +USAGE: get [PATH] [DEVICES](optional) Retrieves object information from API and displays it's information in JSON format. NOTE -If path is not specified then the current path will be used. +If path is not specified then the current path will be used. EXAMPLE get get /Physical/SiteA get ../rack01/device-ibm3 + +OPTION DEVICES: +Retrives devices informations links to an object +It will bind object's name with device's group_name by default +DEVICES take multiple arguments to filter devices + +EXAMPLE + +get /Physical/SiteA/BuildingA/RoomA/Rack01/device-ibm server -> Get all devices where group_name match device-ibm's name +get /Physical/SiteA/BuildingA/RoomA/Rack01/device-ibm%serialNumber server%serial_number -> Binding attributes serialNumber to serial_number +get /Physical/SiteA/BuildingA/RoomA/Rack01/device-ibm server._name=test -> Filter results by device's name + From 27598e138812408adc3a9addb4eae3f9ec74b6da Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Thu, 10 Aug 2023 15:41:36 +0200 Subject: [PATCH 26/35] fix(cli): correct function that never return error --- CLI/controllers/commandController.go | 32 +++++++++++----------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/CLI/controllers/commandController.go b/CLI/controllers/commandController.go index 56167bc33..2c1530c93 100755 --- a/CLI/controllers/commandController.go +++ b/CLI/controllers/commandController.go @@ -142,19 +142,19 @@ func PollObject(path string) (map[string]any, error) { func GetObject(path string) (map[string]any, error) { return GetObjectWithChildren(path, 0) } -func ObjectAttributes(path string)(string, error){ +func ObjectAttributes(path string)(string){ attr := strings.Split(path, "%"); if(len(attr) !=2 ){ - return "name",nil + return "name" } - return attr[1],nil + return attr[1] } -func DevicesAttrs(devices string)(string, error){ +func DevicesAttrs(devices string)(string){ attr := strings.Split(strings.Split(devices,".")[0],"%"); if(len(attr) !=2 ){ - return "group_name",nil + return "group_name" } - return attr[1],nil + return attr[1] } func removeFirstOccurrence(input string, pattern string) string { inputs := strings.Split(input,pattern) @@ -165,20 +165,12 @@ func removeFirstOccurrence(input string, pattern string) string { } func GetDevicesInfo(path string,filters string) (map[string]any, error) { - objAttr ,err:= ObjectAttributes(path) - if err != nil { - return nil, err - } - devicesAttr ,err:= DevicesAttrs(filters) - if err != nil { - return nil, err - } + objAttr := ObjectAttributes(path) + devicesAttr := DevicesAttrs(filters) + path = removeFirstOccurrence(path,"/") - url,err := DevicesUrl(strings.Split(path,"%")[0],objAttr,devicesAttr,filters) - if err != nil { - return nil, err - } + url:= DevicesUrl(strings.Split(path,"%")[0],objAttr,devicesAttr,filters) resp, err := RequestAPI("GET", url, nil, http.StatusOK) if err != nil { if resp != nil && resp.status == http.StatusNotFound { @@ -193,10 +185,10 @@ func GetDevicesInfo(path string,filters string) (map[string]any, error) { } return obj, nil } -func DevicesUrl(path,objAttr,devAttr,filters string) (string, error){ +func DevicesUrl(path,objAttr,devAttr,filters string) string{ query := GenerateDeviceQuery(filters) device := strings.Split(strings.Split(filters, ".")[0],"%")[0] - return "/api/devices/"+device+"/"+path+"/"+objAttr+"/"+devAttr+query,nil + return "/api/devices/"+device+"/"+path+"/"+objAttr+"/"+devAttr+query } func GenerateDeviceQuery(filters string) (string) { From f910a930a6501e756789315b4d8f840e0597fee0 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Thu, 10 Aug 2023 15:48:17 +0200 Subject: [PATCH 27/35] fix(doc): add info for config file of bff --- BFF/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BFF/readme.md b/BFF/readme.md index 1715700c6..5a72370c5 100644 --- a/BFF/readme.md +++ b/BFF/readme.md @@ -11,9 +11,9 @@ Before you begin, set the following environment variables in a .env file or as p You also need a api.json file, that contains an array of `name` and `url` of all API you when to use. -Notice that this minimal configuration you need is an API 'objects': +Notice that this minimal configuration you need is an API name 'objects': -Exemple of api.json: +Exemple of api.json with an API for objects and another for server: ```json [ From 6b1990230722118d67645e37603d6bdee1a520b0 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Fri, 11 Aug 2023 10:46:18 +0200 Subject: [PATCH 28/35] fix(bff): remove useless code --- BFF/main.go | 5 ++--- deploy/docker/docker-compose.yml | 5 ----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/BFF/main.go b/BFF/main.go index 1e627abda..640b7a75e 100644 --- a/BFF/main.go +++ b/BFF/main.go @@ -19,7 +19,7 @@ package main import ( "encoding/json" "fmt" - "io/ioutil" + "io" "ogree-bff/models" "ogree-bff/services" "os" @@ -34,10 +34,9 @@ func GetAPIInfo() ([]models.API) { if err != nil { fmt.Println(err) } - fmt.Println("Successfully Opened users.json") // defer the closing of our jsonFile so that we can parse it later on defer jsonFile.Close() - byteValue, _ := ioutil.ReadAll(jsonFile) + byteValue, _ := io.ReadAll(jsonFile) var api []models.API json.Unmarshal(byteValue, &api) diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index a633cbd9f..893337b21 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -47,8 +47,6 @@ services: environment: SWAGGER_JSON_URL: https://raw.githubusercontent.com/ditrit/OGrEE-Core/${IMAGE_TAG}/BFF/swagger.json restart: on-failure:10 - depends_on: - - ogree_api ogree_webapp: build: @@ -73,8 +71,6 @@ services: - ARANGO_ROOT_PASSWORD=${ARANGO_PASS} volumes: - arangodb-persist:/var/lib/arangodb3 - ports: - - ${ARANGO_PORT}:8529 restart: on-failure:10 @@ -121,6 +117,5 @@ services: volumes: db: arangodb-persist: - external: true From d4f392c7df3dda93acb10c0d0e49c2ad0b9a3ca1 Mon Sep 17 00:00:00 2001 From: helderbetiol Date: Fri, 11 Aug 2023 11:48:13 +0200 Subject: [PATCH 29/35] Add arango profile, expose API --- deploy/docker/docker-compose.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 893337b21..7f4f58d16 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -13,6 +13,8 @@ services: - db_pass=${CUSTOMER_API_PASSWORD} - db=${COMPOSE_PROJECT_NAME} - token_password=${AUTH_SECRET} + ports: + - ${API_PORT}:${API_PORT} depends_on: - ogree_db restart: on-failure:10 @@ -62,10 +64,9 @@ services: - ogree_api restart: on-failure:10 - - arango_db: image: arangodb/arangodb:3.11.2 + profiles: ["arango"] container_name: ${COMPOSE_PROJECT_NAME}_arango_db environment: - ARANGO_ROOT_PASSWORD=${ARANGO_PASS} @@ -73,12 +74,12 @@ services: - arangodb-persist:/var/lib/arangodb3 restart: on-failure:10 - arango_api: build: context: ${CORE_DIR} dockerfile: ${ARANGO_API_BUILD_DIR}/Dockerfile image: arango-api:${IMAGE_TAG} + profiles: ["arango"] restart: always container_name: ${COMPOSE_PROJECT_NAME}_arango_api environment: @@ -100,6 +101,7 @@ services: context: ${CORE_DIR} dockerfile: ${BFF_BUILD_DIR}/Dockerfile image: ogree-bff:${IMAGE_TAG} + profiles: ["arango"] restart: on-failure:10 container_name: ${COMPOSE_PROJECT_NAME}_bff environment: From e21e3ede064bc12022c6639d8f01ea7181723504 Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Fri, 11 Aug 2023 11:33:59 +0200 Subject: [PATCH 30/35] fix(bff): change routes /api/devices by /api/deviceComp/ to avoid conflict with objects request --- BFF/handlers/devices.go | 168 ++++++++++--------- BFF/readme.md | 2 +- BFF/services/router.go | 137 +++++++-------- BFF/swagger.json | 238 +++++++-------------------- CLI/controllers/commandController.go | 2 +- deploy/docker/.env | 3 +- deploy/docker/docker-compose.yml | 5 +- 7 files changed, 213 insertions(+), 342 deletions(-) diff --git a/BFF/handlers/devices.go b/BFF/handlers/devices.go index 8a0cb8991..46f895e91 100644 --- a/BFF/handlers/devices.go +++ b/BFF/handlers/devices.go @@ -1,12 +1,13 @@ package handlers import ( - "ogree-bff/controllers" "net/http" + "ogree-bff/controllers" + "github.com/gin-gonic/gin" ) -// swagger:operation GET /devices/{entity} Devices Devices +// swagger:operation GET /deviceComps/{entity} Devices Devices // Get Devices list // // --- @@ -58,10 +59,10 @@ func GetDevices(c *gin.Context) { c.IndentedJSON(http.StatusBadRequest, gin.H{"message": entity + " has not database"}) return } - controllers.GetDevice(c, deviceURL+"/api/devices","GET") + controllers.GetDevice(c, deviceURL+"/api/devices", "GET") } -// swagger:operation GET /devices/{entity}/ConnecteTo/{device} Devices GetDevicesConnectedTo +// swagger:operation GET /deviceComp/{entity}/ConnecteTo/{device} Devices GetDevicesConnectedTo // Get Devices connected to a device // // --- @@ -101,16 +102,17 @@ func GetDevices(c *gin.Context) { // - Bearer: [] // // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func GetDevicesConnectedTo(c *gin.Context) { entity := c.Param("entity") @@ -120,10 +122,10 @@ func GetDevicesConnectedTo(c *gin.Context) { c.IndentedJSON(http.StatusBadRequest, gin.H{"message": entity + " has not database"}) return } - controllers.GetDevice(c, deviceURL+"/api/devices/ConnecteTo/"+id,"GET") + controllers.GetDevice(c, deviceURL+"/api/deviceComp/ConnecteTo/"+id, "GET") } -// swagger:operation POST /devices/{entity} Devices CreateDevices +// swagger:operation POST /deviceComp/{entity} Devices CreateDevices // Create new Devices // // --- @@ -144,16 +146,17 @@ func GetDevicesConnectedTo(c *gin.Context) { // example: '{"_name": "server", "group_name": "exwipen22","created": "2022-07-18"}' // // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func CreateDevices(c *gin.Context) { entity := c.Param("entity") @@ -162,10 +165,10 @@ func CreateDevices(c *gin.Context) { c.IndentedJSON(http.StatusBadRequest, gin.H{"message": entity + " has not database"}) return } - controllers.PostDevice(c, deviceURL+"/api/devices","POST") + controllers.PostDevice(c, deviceURL+"/api/devices", "POST") } -// swagger:operation DELETE /devices/{entity}{device} Devices DeleteDevices +// swagger:operation DELETE /deviceComp/{entity}{device} Devices DeleteDevices // Delete Devices by key // // --- @@ -185,16 +188,17 @@ func CreateDevices(c *gin.Context) { // - Bearer: [] // // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func DeleteDevice(c *gin.Context) { entity := c.Param("entity") id := c.Param("id") @@ -203,7 +207,7 @@ func DeleteDevice(c *gin.Context) { c.IndentedJSON(http.StatusBadRequest, gin.H{"message": entity + " has not database"}) return } - controllers.GetDevice(c, deviceURL+"/api/devices/"+id,"DELETE") + controllers.GetDevice(c, deviceURL+"/api/deviceComp/"+id, "DELETE") } // swagger:operation GET /Connections Devices GetConnections @@ -231,16 +235,17 @@ func DeleteDevice(c *gin.Context) { // - Bearer: [] // // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func GetConnections(c *gin.Context) { controllers.Get(c, "devices") } @@ -261,16 +266,17 @@ func GetConnections(c *gin.Context) { // example: '{"_from": "devices/123", "_to": "devices/111"}' // // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func CreateConnections(c *gin.Context) { controllers.Post(c, "devices") } @@ -290,21 +296,22 @@ func CreateConnections(c *gin.Context) { // type: string // // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func DeleteConnections(c *gin.Context) { controllers.Delete(c, "devices") } -// swagger:operation GET /devices/{entity}/{obj}/{objAttr}/{deviceAttr} Devices GetDeviceBindingObject +// swagger:operation GET /deviceComp/{entity}/{obj}/{objAttr}/{deviceAttr} Devices GetDeviceBindingObject // Get Devices list // // --- @@ -349,16 +356,17 @@ func DeleteConnections(c *gin.Context) { // - Bearer: [] // // responses: -// '200': -// description: successful -// schema: -// items: -// "$ref": "#/definitions/SuccessResponse" -// '500': -// description: Error -// schema: -// items: -// "$ref": "#/definitions/ErrorResponse" +// +// '200': +// description: successful +// schema: +// items: +// "$ref": "#/definitions/SuccessResponse" +// '500': +// description: Error +// schema: +// items: +// "$ref": "#/definitions/ErrorResponse" func GetDeviceBindingObject(c *gin.Context) { controllers.DeviceBindingObject(c) diff --git a/BFF/readme.md b/BFF/readme.md index 5a72370c5..53881c952 100644 --- a/BFF/readme.md +++ b/BFF/readme.md @@ -36,7 +36,7 @@ The server should start and be ready to accept requests. ### Bindings Data between objects's API and another -- GET /api/devices/:apiName/:objects/:objectAttributes/:devicesAttributes : Retrieve the list of all devices in the database connect to apiName where the specific attributes of the objects match the specific attributes of devices +- GET /api/deviceComp/:apiName/:objects/:objectAttributes/:devicesAttributes : Retrieve the list of all devices in the database connect to apiName where the specific attributes of the objects match the specific attributes of devices diff --git a/BFF/services/router.go b/BFF/services/router.go index 01e1d4a5d..37390446a 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -1,7 +1,6 @@ package services import ( - "net/http" "ogree-bff/handlers" "ogree-bff/models" @@ -11,13 +10,11 @@ import ( "github.com/gin-gonic/gin" ) - - func JwtAuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { err := token.TokenValid(c) if err != nil { - c.IndentedJSON(http.StatusUnauthorized,gin.H{"message":"Unauthorized"}) + c.IndentedJSON(http.StatusUnauthorized, gin.H{"message": "Unauthorized"}) c.Abort() return } @@ -25,125 +22,115 @@ func JwtAuthMiddleware() gin.HandlerFunc { } } - func APIMiddleware(apiList []models.API) gin.HandlerFunc { - return func (c *gin.Context){ + return func(c *gin.Context) { for _, api := range apiList { - c.Set(api.Name,api.URL) - + c.Set(api.Name, api.URL) + } c.Next() - + } } -func initDevices(protected, unprotected *gin.RouterGroup){ - - protected.GET("/devices/:entity",handlers.GetDevices) - protected.GET("/devices/:entity/ConnecteTo/:id",handlers.GetDevicesConnectedTo) - protected.POST("/devices/:entity",handlers.CreateDevices) - protected.DELETE("/devices/:entity/:id",handlers.DeleteDevice) - - protected.GET("/Connections",handlers.GetConnections) - protected.POST("/Connections",handlers.CreateConnections) - protected.DELETE("/Connections/:id",handlers.DeleteConnections) - - protected.GET("/devices/:entity/:obj/:objAttr/:deviceAttr",handlers.GetDeviceBindingObject) +func initDevices(protected, unprotected *gin.RouterGroup) { + + protected.GET("/deviceComp/:entity", handlers.GetDevices) + protected.GET("/deviceComp/:entity/ConnecteTo/:id", handlers.GetDevicesConnectedTo) + protected.POST("/deviceComp/:entity", handlers.CreateDevices) + protected.DELETE("/deviceComp/:entity/:id", handlers.DeleteDevice) + + protected.GET("/Connections", handlers.GetConnections) + protected.POST("/Connections", handlers.CreateConnections) + protected.DELETE("/Connections/:id", handlers.DeleteConnections) + + protected.GET("/deviceComp/:entity/:obj/:objAttr/:deviceAttr", handlers.GetDeviceBindingObject) } -func initAuth(protected, unprotected *gin.RouterGroup){ - - protected.GET("/token/valid",handlers.ValidToken) - protected.POST("/users/password/reset",handlers.ResetUserPassword) - protected.POST("/users/password/change",handlers.ModifyUserPassword) +func initAuth(protected, unprotected *gin.RouterGroup) { - unprotected.POST("/login",handlers.Login) - unprotected.POST("/users/password/forgot",handlers.UserForgotPassword) + protected.GET("/token/valid", handlers.ValidToken) + protected.POST("/users/password/reset", handlers.ResetUserPassword) + protected.POST("/users/password/change", handlers.ModifyUserPassword) + + unprotected.POST("/login", handlers.Login) + unprotected.POST("/users/password/forgot", handlers.UserForgotPassword) } -func initOrganization(protected, unprotected *gin.RouterGroup){ - protected.POST("/users",handlers.CreateAccount) - protected.POST("/users/bulk",handlers.CreateBulk) - protected.GET("/users",handlers.GetAllAccounts) - protected.DELETE("/users/:user",handlers.RemoveAccount) - protected.PATCH("/users/:user",handlers.ModifyUserRoles) - protected.POST("/domains/bulk",handlers.CreateBulkDomain) - protected.GET("/hierarchy/domains",handlers.GetCompleteDomainHierarchy) +func initOrganization(protected, unprotected *gin.RouterGroup) { + protected.POST("/users", handlers.CreateAccount) + protected.POST("/users/bulk", handlers.CreateBulk) + protected.GET("/users", handlers.GetAllAccounts) + protected.DELETE("/users/:user", handlers.RemoveAccount) + protected.PATCH("/users/:user", handlers.ModifyUserRoles) + protected.POST("/domains/bulk", handlers.CreateBulkDomain) + protected.GET("/hierarchy/domains", handlers.GetCompleteDomainHierarchy) } -func initFlutterApp(protected, unprotected *gin.RouterGroup){ - protected.POST("/projects",handlers.CreateProjects) - protected.GET("/projects",handlers.GetProjects) - protected.DELETE("/projects/*id",handlers.DeleteProjects) - protected.PUT("/projects/*id",handlers.UpdateProjects) +func initFlutterApp(protected, unprotected *gin.RouterGroup) { + protected.POST("/projects", handlers.CreateProjects) + protected.GET("/projects", handlers.GetProjects) + protected.DELETE("/projects/*id", handlers.DeleteProjects) + protected.PUT("/projects/*id", handlers.UpdateProjects) } -func initAbout(protected, unprotected *gin.RouterGroup){ - protected.GET("/stats",handlers.GetStats) - protected.POST("/versions",handlers.GetAPIVersion) +func initAbout(protected, unprotected *gin.RouterGroup) { + protected.GET("/stats", handlers.GetStats) + protected.POST("/versions", handlers.GetAPIVersion) } -func initObjects(protected, unprotected *gin.RouterGroup){ +func initObjects(protected, unprotected *gin.RouterGroup) { - protected.GET("/:entity",handlers.GetAllEntities) - protected.POST("/:entity",handlers.CreateObject) + protected.GET("/:entity", handlers.GetAllEntities) + protected.POST("/:entity", handlers.CreateObject) - protected.GET("/objects/*hierarchyName",handlers.GetGenericObject) + protected.GET("/objects/*hierarchyName", handlers.GetGenericObject) - protected.GET("/:entity/*id",handlers.GetEntity) - protected.DELETE("/:entity/*id",handlers.DeleteObject) - protected.PATCH("/:entity/*id",handlers.PartialUpdateObject) - protected.PUT("/:entity/*id",handlers.UpdateObject) + protected.GET("/:entity/*id", handlers.GetEntity) + protected.DELETE("/:entity/*id", handlers.DeleteObject) + protected.PATCH("/:entity/*id", handlers.PartialUpdateObject) + protected.PUT("/:entity/*id", handlers.UpdateObject) - protected.GET("/tempunits/*id",handlers.GetTempUnit) + protected.GET("/tempunits/*id", handlers.GetTempUnit) //protected.GET("/:entity/:id/:subent",handlers.GetEntitiesOfAncestor) - - protected.GET("/hierarchy",handlers.GetCompleteHierarchy) - protected.GET("/hierarchy/attributes",handlers.GetCompleteHierarchyAttrs) + protected.GET("/hierarchy", handlers.GetCompleteHierarchy) + protected.GET("/hierarchy/attributes", handlers.GetCompleteHierarchyAttrs) //protected.GET("/:entity/:id/:HierarchalPath",handlers.GetEntitiesUsingNamesOfParents) - protected.POST("/validate/*entity",handlers.ValidateObject) - - -} + protected.POST("/validate/*entity", handlers.ValidateObject) +} -func InitRouter(apiList []models.API,env string ) *gin.Engine { +func InitRouter(apiList []models.API, env string) *gin.Engine { if env == "production" { gin.SetMode(gin.ReleaseMode) } - router := gin.Default() protected := router.Group("/api") protected.Use(JwtAuthMiddleware()) protected.Use(APIMiddleware(apiList)) - + unprotected := router.Group("/api") unprotected.Use(APIMiddleware(apiList)) - initDevices(protected,unprotected) - initAuth(protected,unprotected) - initOrganization(protected,unprotected) - initObjects(protected,unprotected) - initAbout(protected,unprotected) - + initDevices(protected, unprotected) + initAuth(protected, unprotected) + initOrganization(protected, unprotected) + initObjects(protected, unprotected) + initAbout(protected, unprotected) //init healthcheck route - unprotected.GET("/health",func(c *gin.Context){ - c.String(http.StatusAccepted,"") + unprotected.GET("/health", func(c *gin.Context) { + c.String(http.StatusAccepted, "") }) - swagger := handlers.SwaggerHandler() router.Use(gin.WrapH(swagger)) - - - return router } diff --git a/BFF/swagger.json b/BFF/swagger.json index d47024c89..a66d1e230 100644 --- a/BFF/swagger.json +++ b/BFF/swagger.json @@ -47,25 +47,7 @@ "name": "_to", "in": "query" } - ], - "responses": { - "200": { - "description": "successful", - "schema": { - "items": { - "$ref": "#/definitions/SuccessResponse" - } - } - }, - "500": { - "description": "Error", - "schema": { - "items": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - } + ] }, "post": { "security": [ @@ -87,25 +69,7 @@ "in": "body", "required": true } - ], - "responses": { - "200": { - "description": "successful", - "schema": { - "items": { - "$ref": "#/definitions/SuccessResponse" - } - } - }, - "500": { - "description": "Error", - "schema": { - "items": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - } + ] } }, "/Connections/{connection}": { @@ -128,91 +92,10 @@ "in": "path", "required": true } - ], - "responses": { - "200": { - "description": "successful", - "schema": { - "items": { - "$ref": "#/definitions/SuccessResponse" - } - } - }, - "500": { - "description": "Error", - "schema": { - "items": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - } + ] } }, - "/devices/{entity}": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Get Devices list", - "tags": [ - "Devices" - ], - "operationId": "Devices", - "parameters": [ - { - "type": "string", - "description": "Key of device", - "name": "_key", - "in": "query" - }, - { - "type": "string", - "description": "database to retrieve devices", - "name": "entity", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Name of device", - "name": "_name", - "in": "query" - }, - { - "type": "string", - "description": "Group_name of device", - "name": "group_name", - "in": "query" - }, - { - "type": "string", - "description": "Serial number of device", - "name": "serial", - "in": "query" - } - ], - "responses": { - "200": { - "description": "successful", - "schema": { - "items": { - "$ref": "#/definitions/SuccessResponse" - } - } - }, - "500": { - "description": "Error", - "schema": { - "items": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - } - }, + "/deviceComp/{entity}": { "post": { "security": [ { @@ -240,28 +123,10 @@ "in": "body", "required": true } - ], - "responses": { - "200": { - "description": "successful", - "schema": { - "items": { - "$ref": "#/definitions/SuccessResponse" - } - } - }, - "500": { - "description": "Error", - "schema": { - "items": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - } + ] } }, - "/devices/{entity}/ConnecteTo/{device}": { + "/deviceComp/{entity}/ConnecteTo/{device}": { "get": { "security": [ { @@ -312,28 +177,10 @@ "name": "serial", "in": "query" } - ], - "responses": { - "200": { - "description": "successful", - "schema": { - "items": { - "$ref": "#/definitions/SuccessResponse" - } - } - }, - "500": { - "description": "Error", - "schema": { - "items": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - } + ] } }, - "/devices/{entity}/{obj}/{objAttr}/{deviceAttr}": { + "/deviceComp/{entity}/{obj}/{objAttr}/{deviceAttr}": { "get": { "security": [ { @@ -391,28 +238,10 @@ "name": "serial", "in": "query" } - ], - "responses": { - "200": { - "description": "successful", - "schema": { - "items": { - "$ref": "#/definitions/SuccessResponse" - } - } - }, - "500": { - "description": "Error", - "schema": { - "items": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - } + ] } }, - "/devices/{entity}{device}": { + "/deviceComp/{entity}{device}": { "delete": { "security": [ { @@ -439,6 +268,53 @@ "in": "path", "required": true } + ] + } + }, + "/deviceComps/{entity}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get Devices list", + "tags": [ + "Devices" + ], + "operationId": "Devices", + "parameters": [ + { + "type": "string", + "description": "Key of device", + "name": "_key", + "in": "query" + }, + { + "type": "string", + "description": "database to retrieve devices", + "name": "entity", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Name of device", + "name": "_name", + "in": "query" + }, + { + "type": "string", + "description": "Group_name of device", + "name": "group_name", + "in": "query" + }, + { + "type": "string", + "description": "Serial number of device", + "name": "serial", + "in": "query" + } ], "responses": { "200": { diff --git a/CLI/controllers/commandController.go b/CLI/controllers/commandController.go index 2c1530c93..c24671a61 100755 --- a/CLI/controllers/commandController.go +++ b/CLI/controllers/commandController.go @@ -188,7 +188,7 @@ func GetDevicesInfo(path string,filters string) (map[string]any, error) { func DevicesUrl(path,objAttr,devAttr,filters string) string{ query := GenerateDeviceQuery(filters) device := strings.Split(strings.Split(filters, ".")[0],"%")[0] - return "/api/devices/"+device+"/"+path+"/"+objAttr+"/"+devAttr+query + return "/api/deviceComp/"+device+"/"+path+"/"+objAttr+"/"+devAttr+query } func GenerateDeviceQuery(filters string) (string) { diff --git a/deploy/docker/.env b/deploy/docker/.env index 74cb5cf88..16dd65846 100644 --- a/deploy/docker/.env +++ b/deploy/docker/.env @@ -13,10 +13,9 @@ IMAGE_TAG=main #ARANGODB_ ARANGO_API_BUILD_DIR=ARANGO_API ARANGO_API_PORT=8080 -ARANGO_PASS=password +ARANGO_PASS=ogree ARANGO_USER=root ARANGO_DB=_system -ARANGO_PORT=8529 #BFF BFF_BUILD_DIR=BFF diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 7f4f58d16..0a892d6ee 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -73,6 +73,7 @@ services: volumes: - arangodb-persist:/var/lib/arangodb3 restart: on-failure:10 + arango_api: build: @@ -84,14 +85,14 @@ services: container_name: ${COMPOSE_PROJECT_NAME}_arango_api environment: - ENV=production - - ARANGO_URL=http://${COMPOSE_PROJECT_NAME}_arango_db:${ARANGO_PORT} + - ARANGO_URL=http://${COMPOSE_PROJECT_NAME}_arango_db:8529 - ARANGO_DATABASE=${ARANGO_DB} - ARANGO_USER=${ARANGO_USER} - ARANGO_PASSWORD=${ARANGO_PASS} - API_SECRET=${AUTH_SECRET} - API_PORT=${ARANGO_API_PORT} healthcheck: - test: ["CMD", "curl","-f","http://${COMPOSE_PROJECT_NAME}_arango_db:5829/_api/version"] + test: ["CMD", "curl","-f","http://${COMPOSE_PROJECT_NAME}_arango_db:8529/_api/version"] timeout: 30s interval: 1m retries: 3 From 2bc9b7c276f9cf64ffc998335acf7a15484c0b1e Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Fri, 11 Aug 2023 14:57:39 +0200 Subject: [PATCH 31/35] fix(bff): add allowAllCrossOrigin --- BFF/go.mod | 1 + BFF/go.sum | 25 +++++++++++++++++++++++++ BFF/services/router.go | 7 ++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/BFF/go.mod b/BFF/go.mod index d1eeb79ad..134365fb4 100644 --- a/BFF/go.mod +++ b/BFF/go.mod @@ -15,6 +15,7 @@ require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/cors v1.4.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/errors v0.20.3 // indirect diff --git a/BFF/go.sum b/BFF/go.sum index 90d022503..5fbef52c3 100644 --- a/BFF/go.sum +++ b/BFF/go.sum @@ -17,8 +17,11 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= +github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= @@ -56,10 +59,14 @@ github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -87,6 +94,7 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -114,9 +122,12 @@ github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -126,6 +137,7 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 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.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -142,8 +154,10 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -151,6 +165,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -172,6 +188,8 @@ github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -192,11 +210,13 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= 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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= @@ -217,12 +237,15 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/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= @@ -235,11 +258,13 @@ golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.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-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/BFF/services/router.go b/BFF/services/router.go index 37390446a..69eccaf9d 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -6,7 +6,7 @@ import ( "ogree-bff/models" "ogree-bff/utils/token" - // driver "github.com/arangodb/go-driver" + "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" ) @@ -111,6 +111,11 @@ func InitRouter(apiList []models.API, env string) *gin.Engine { router := gin.Default() + corsConfig := cors.DefaultConfig() + corsConfig.AllowAllOrigins = true + router.Use(cors.New(corsConfig)) + + protected := router.Group("/api") protected.Use(JwtAuthMiddleware()) protected.Use(APIMiddleware(apiList)) From a10c04d9254705312db59f20f0d435c0c186361c Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Fri, 11 Aug 2023 15:15:59 +0200 Subject: [PATCH 32/35] fix(bff): add options to cors --- BFF/services/router.go | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/BFF/services/router.go b/BFF/services/router.go index 69eccaf9d..c82caa848 100644 --- a/BFF/services/router.go +++ b/BFF/services/router.go @@ -6,7 +6,6 @@ import ( "ogree-bff/models" "ogree-bff/utils/token" - "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" ) @@ -33,6 +32,24 @@ func APIMiddleware(apiList []models.API) gin.HandlerFunc { } } + +func CORSMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") + c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") + c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT,DELETE") + + if c.Request.Method == "OPTIONS" { + c.AbortWithStatus(204) + return + } + + c.Next() + } +} + + func initDevices(protected, unprotected *gin.RouterGroup) { protected.GET("/deviceComp/:entity", handlers.GetDevices) @@ -110,16 +127,13 @@ func InitRouter(apiList []models.API, env string) *gin.Engine { } router := gin.Default() + router.Use(CORSMiddleware()) - corsConfig := cors.DefaultConfig() - corsConfig.AllowAllOrigins = true - router.Use(cors.New(corsConfig)) - - protected := router.Group("/api") protected.Use(JwtAuthMiddleware()) protected.Use(APIMiddleware(apiList)) + unprotected := router.Group("/api") unprotected.Use(APIMiddleware(apiList)) From 1554356ba7ff69f1aa7bf1b10c89dffec6742640 Mon Sep 17 00:00:00 2001 From: helderbetiol Date: Fri, 11 Aug 2023 16:05:06 +0200 Subject: [PATCH 33/35] Add Arango+BFF to SuperAdmin APP --- APP/ogree_app/lib/models/tenant.dart | 27 +++++++----- .../tenants/popups/create_tenant_popup.dart | 16 +++++-- .../tenants/popups/update_tenant_popup.dart | 6 ++- APP/ogree_app_backend/api.go | 2 + .../backend-assets/bff-api-list-template.txt | 4 ++ .../backend-assets/docker-env-template.txt | 12 ++++++ APP/ogree_app_backend/tenant.go | 43 ++++++++++++++++--- deploy/docker/.env | 1 + deploy/docker/docker-compose.yml | 2 +- 9 files changed, 89 insertions(+), 24 deletions(-) create mode 100644 APP/ogree_app_backend/backend-assets/bff-api-list-template.txt diff --git a/APP/ogree_app/lib/models/tenant.dart b/APP/ogree_app/lib/models/tenant.dart index 77e67dfb7..4eac23879 100644 --- a/APP/ogree_app/lib/models/tenant.dart +++ b/APP/ogree_app/lib/models/tenant.dart @@ -15,6 +15,7 @@ class Tenant { String docUrl; String docPort; String imageTag; + bool hasBff; TenantStatus? status; Tenant( @@ -29,6 +30,7 @@ class Tenant { this.docUrl, this.docPort, this.imageTag, + this.hasBff, {this.status}); Map toMap() { @@ -44,22 +46,25 @@ class Tenant { 'docUrl': docUrl, 'docPort': docPort, 'imageTag': imageTag, + 'hasBff': hasBff, }; } factory Tenant.fromMap(Map map) { return Tenant( - map['name'].toString(), - map['customerPassword'].toString(), - map['apiUrl'].toString(), - map['webUrl'].toString(), - map['apiPort'].toString(), - map['webPort'].toString(), - map['hasWeb'], - map['hasDoc'], - map['docUrl'].toString(), - map['docPort'].toString(), - map['imageTag'].toString()); + map['name'].toString(), + map['customerPassword'].toString(), + map['apiUrl'].toString(), + map['webUrl'].toString(), + map['apiPort'].toString(), + map['webPort'].toString(), + map['hasWeb'], + map['hasDoc'], + map['docUrl'].toString(), + map['docPort'].toString(), + map['imageTag'].toString(), + map['hasBff'], + ); } String toJson() => json.encode(toMap()); diff --git a/APP/ogree_app/lib/widgets/tenants/popups/create_tenant_popup.dart b/APP/ogree_app/lib/widgets/tenants/popups/create_tenant_popup.dart index ea1be5e8e..95fe86e44 100644 --- a/APP/ogree_app/lib/widgets/tenants/popups/create_tenant_popup.dart +++ b/APP/ogree_app/lib/widgets/tenants/popups/create_tenant_popup.dart @@ -28,6 +28,7 @@ class _CreateTenantPopupState extends State { String _docPort = ""; bool _hasWeb = true; bool _hasDoc = false; + bool _hasBff = false; bool _isLoading = false; PlatformFile? _loadedImage; String _imageTag = "main"; @@ -78,8 +79,8 @@ class _CreateTenantPopupState extends State { alignment: WrapAlignment.center, crossAxisAlignment: WrapCrossAlignment.center, children: [ - getCheckBox("API", true, (_) {}, - enabled: false), + // getCheckBox("API", true, (_) {}, + // enabled: false), getCheckBox( "WEB", _hasWeb, @@ -92,6 +93,12 @@ class _CreateTenantPopupState extends State { (value) => setState(() { _hasDoc = value!; })), + getCheckBox( + "Arango", + _hasBff, + (value) => setState(() { + _hasBff = value!; + })), ], ), const SizedBox(height: 10), @@ -259,7 +266,8 @@ class _CreateTenantPopupState extends State { _hasDoc, _docUrl, _docPort, - _imageTag)); + _imageTag, + _hasBff)); switch (result) { case Success(value: final value): widget.parentCallback(); @@ -278,7 +286,7 @@ class _CreateTenantPopupState extends State { getCheckBox(String title, bool value, Function(bool?) onChange, {bool enabled = true}) { return SizedBox( - width: 95, + width: 110, child: CheckboxListTile( activeColor: Colors.blue.shade600, contentPadding: EdgeInsets.zero, diff --git a/APP/ogree_app/lib/widgets/tenants/popups/update_tenant_popup.dart b/APP/ogree_app/lib/widgets/tenants/popups/update_tenant_popup.dart index 6fef88ed7..5e4417969 100644 --- a/APP/ogree_app/lib/widgets/tenants/popups/update_tenant_popup.dart +++ b/APP/ogree_app/lib/widgets/tenants/popups/update_tenant_popup.dart @@ -54,7 +54,7 @@ class _UpdateTenantPopupState extends State { alignment: WrapAlignment.start, crossAxisAlignment: WrapCrossAlignment.center, children: [ - getCheckBox("API", true, (_) {}, enabled: false), + // getCheckBox("API", true, (_) {}, enabled: false), getCheckBox( "WEB", widget.tenant.hasWeb, @@ -67,6 +67,8 @@ class _UpdateTenantPopupState extends State { (value) => setState(() { widget.tenant.hasDoc = value!; })), + getCheckBox("Arango", widget.tenant.hasBff, (_) {}, + enabled: false), ], ), getFormField( @@ -182,7 +184,7 @@ class _UpdateTenantPopupState extends State { getCheckBox(String title, bool value, Function(bool?) onChange, {bool enabled = true}) { return SizedBox( - width: 95, + width: 105, child: CheckboxListTile( activeColor: Colors.blue.shade600, contentPadding: EdgeInsets.zero, diff --git a/APP/ogree_app_backend/api.go b/APP/ogree_app_backend/api.go index 257292bc2..db652c107 100644 --- a/APP/ogree_app_backend/api.go +++ b/APP/ogree_app_backend/api.go @@ -15,6 +15,7 @@ import ( ) var tmplt *template.Template +var bfftmplt *template.Template var apptmplt *template.Template var servertmplt *template.Template var netboxtmplt *template.Template @@ -35,6 +36,7 @@ func init() { // []byte("password"), bcrypt.DefaultCost) // println(string(hashedPassword)) tmplt = template.Must(template.ParseFiles("backend-assets/docker-env-template.txt")) + bfftmplt = template.Must(template.ParseFiles("backend-assets/bff-api-list-template.txt")) apptmplt = template.Must(template.ParseFiles("flutter-assets/flutter-env-template.txt")) servertmplt = template.Must(template.ParseFiles("backend-assets/template.service")) netboxtmplt = template.Must(template.ParseFiles("tools-assets/netbox-docker-template.txt")) diff --git a/APP/ogree_app_backend/backend-assets/bff-api-list-template.txt b/APP/ogree_app_backend/backend-assets/bff-api-list-template.txt new file mode 100644 index 000000000..cd29bee03 --- /dev/null +++ b/APP/ogree_app_backend/backend-assets/bff-api-list-template.txt @@ -0,0 +1,4 @@ +[ + {"name":"server", "url": "http://{{.Name}}_arango_api:8080"}, + {"name":"objects", "url": "http://{{.Name}}_api:{{.ApiPort}}"} +] \ No newline at end of file diff --git a/APP/ogree_app_backend/backend-assets/docker-env-template.txt b/APP/ogree_app_backend/backend-assets/docker-env-template.txt index 4fade7380..f6516ebba 100644 --- a/APP/ogree_app_backend/backend-assets/docker-env-template.txt +++ b/APP/ogree_app_backend/backend-assets/docker-env-template.txt @@ -9,3 +9,15 @@ API_EXTERNALURL={{.ApiUrl}} COMPOSE_PROJECT_NAME={{.Name}} APP_ASSETS_DIR={{.AssetsDir}} IMAGE_TAG={{.ImageTag}} + +ARANGO_API_BUILD_DIR=ARANGO_API +ARANGO_API_PORT=8080 +ARANGO_PASS=ogree +ARANGO_USER=root +ARANGO_DB=_system + +BFF_BUILD_DIR=BFF +BFF_PORT={{.BffPort}} +BFF_API_LIST={{.BffApiListFile}} + +AUTH_SECRET=myAwesomeApiSecret \ No newline at end of file diff --git a/APP/ogree_app_backend/tenant.go b/APP/ogree_app_backend/tenant.go index ddcd9efe2..8978a8db5 100644 --- a/APP/ogree_app_backend/tenant.go +++ b/APP/ogree_app_backend/tenant.go @@ -12,6 +12,7 @@ import ( "os" "os/exec" "regexp" + "strconv" "strings" "time" @@ -27,10 +28,13 @@ type tenant struct { WebPort string `json:"webPort"` DocUrl string `json:"docUrl"` DocPort string `json:"docPort"` + BffPort string `json:"bffPort"` HasWeb bool `json:"hasWeb"` HasDoc bool `json:"hasDoc"` + HasBff bool `json:"hasBff"` AssetsDir string `json:"assetsDir"` ImageTag string `json:"imageTag"` + BffApiListFile string } type container struct { @@ -182,6 +186,12 @@ func addTenant(c *gin.Context) { func dockerCreateTenant(newTenant tenant) string { tenantLower := strings.ToLower(newTenant.Name) + appDeployDir := DOCKER_DIR + "app-deploy/" + tenantLower + "/" + err := os.MkdirAll(appDeployDir, 0755) + if err != nil && !strings.Contains(err.Error(), "already") { + println(err.Error()) + } + // Image tagging if newTenant.ImageTag == "" { newTenant.ImageTag = "main" @@ -193,29 +203,50 @@ func dockerCreateTenant(newTenant tenant) string { args = append(args, "--profile") args = append(args, "web") // Create flutter assets folder - newTenant.AssetsDir = DOCKER_DIR + "app-deploy/" + tenantLower + newTenant.AssetsDir = appDeployDir + "flutter" addAppAssets(newTenant) } else { // docker does not accept it empty, even if it wont be created newTenant.AssetsDir = DOCKER_DIR } + if newTenant.HasDoc { args = append(args, "--profile") args = append(args, "doc") } + + if newTenant.HasBff { + args = append(args, "--profile") + args = append(args, "arango") + if newTenant.BffPort == "" { + // Set BFF and API ports + newTenant.BffPort = newTenant.ApiPort + port, _ := strconv.Atoi(newTenant.ApiPort) + newTenant.ApiPort = strconv.Itoa(port + 1) + } + file, _ := os.Create(appDeployDir + tenantLower + "-bff-api-list.json") + err := bfftmplt.Execute(file, newTenant) + if err != nil { + fmt.Println("Error creating bff api list file: " + err.Error()) + newTenant.BffApiListFile = "./bff_api_list.json" + } else { + newTenant.BffApiListFile = "./app-deploy/" + tenantLower + "/" + tenantLower + "-bff-api-list.json" + } + file.Close() + } args = append(args, "up") args = append(args, "--build") args = append(args, "-d") // Create .env file file, _ := os.Create(DOCKER_DIR + ".env") - err := tmplt.Execute(file, newTenant) + err = tmplt.Execute(file, newTenant) if err != nil { panic(err) } file.Close() // Create tenantName.env as a copy - file, _ = os.Create(DOCKER_DIR + tenantLower + ".env") + file, _ = os.Create(appDeployDir + tenantLower + ".env") err = tmplt.Execute(file, newTenant) if err != nil { fmt.Println("Error creating .env copy: " + err.Error()) @@ -285,7 +316,7 @@ func addTenantLogo(c *gin.Context) { c.String(http.StatusInternalServerError, err.Error()) } // Make sure destination dir is created - assetsDir := DOCKER_DIR + "app-deploy/" + tenantName + assetsDir := DOCKER_DIR + "app-deploy/" + tenantName + "/flutter" err = os.MkdirAll(assetsDir, 0755) if err != nil && !strings.Contains(err.Error(), "already") { c.String(http.StatusInternalServerError, err.Error()) @@ -302,7 +333,7 @@ func removeTenant(c *gin.Context) { tenantName := strings.ToLower(c.Param("name")) // Stop and remove containers - for _, str := range []string{"_webapp", "_api", "_db", "_doc"} { + for _, str := range []string{"_webapp", "_api", "_db", "_doc", "_bff", "_arango_api", "_arango_db"} { cmd := exec.Command("docker", "rm", "--force", strings.ToLower(tenantName)+str) cmd.Dir = DOCKER_DIR var stderr bytes.Buffer @@ -315,7 +346,7 @@ func removeTenant(c *gin.Context) { } // Remove assets - os.RemoveAll(DOCKER_DIR + "app-deploy/" + tenantName) + os.RemoveAll(DOCKER_DIR + "app-deploy/" + tenantName + "/flutter") os.Remove(DOCKER_DIR + tenantName + ".env") // Update local file diff --git a/deploy/docker/.env b/deploy/docker/.env index 16dd65846..ed7fec830 100644 --- a/deploy/docker/.env +++ b/deploy/docker/.env @@ -20,6 +20,7 @@ ARANGO_DB=_system #BFF BFF_BUILD_DIR=BFF BFF_PORT=8085 +BFF_API_LIST=./bff_api_list.json #AUTH AUTH_SECRET=myAwesomeApiSecret diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 0a892d6ee..a718eafa4 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -110,7 +110,7 @@ services: - BFF_PORT=${BFF_PORT} - BFF_SECRET=${AUTH_SECRET} volumes: - - ./bff_api_list.json:/bin/api.json + - ${BFF_API_LIST}:/bin/api.json depends_on: - ogree_api - arango_api From ef5c2be2f36424658b6be5aba6a1affcecd88e2e Mon Sep 17 00:00:00 2001 From: helderbetiol Date: Fri, 11 Aug 2023 17:05:19 +0200 Subject: [PATCH 34/35] Fix superadmin deploy without Arango --- APP/ogree_app_backend/tenant.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/APP/ogree_app_backend/tenant.go b/APP/ogree_app_backend/tenant.go index 8978a8db5..43cb87de0 100644 --- a/APP/ogree_app_backend/tenant.go +++ b/APP/ogree_app_backend/tenant.go @@ -215,25 +215,28 @@ func dockerCreateTenant(newTenant tenant) string { args = append(args, "doc") } + // Default values, empty vars not accepted on docker compose + newTenant.BffApiListFile = "./bff_api_list.json" + newTenant.BffPort = newTenant.ApiPort if newTenant.HasBff { args = append(args, "--profile") args = append(args, "arango") if newTenant.BffPort == "" { - // Set BFF and API ports - newTenant.BffPort = newTenant.ApiPort + // Set API Port to BFF Port + 1 port, _ := strconv.Atoi(newTenant.ApiPort) newTenant.ApiPort = strconv.Itoa(port + 1) } + // Create bff api list json file file, _ := os.Create(appDeployDir + tenantLower + "-bff-api-list.json") err := bfftmplt.Execute(file, newTenant) if err != nil { fmt.Println("Error creating bff api list file: " + err.Error()) - newTenant.BffApiListFile = "./bff_api_list.json" } else { newTenant.BffApiListFile = "./app-deploy/" + tenantLower + "/" + tenantLower + "-bff-api-list.json" } file.Close() } + args = append(args, "up") args = append(args, "--build") args = append(args, "-d") From c7a713b81eb8b8c9c817446bf49c5bd2cd9cde9f Mon Sep 17 00:00:00 2001 From: Valentin Beauchamp Date: Thu, 17 Aug 2023 08:15:07 +0200 Subject: [PATCH 35/35] fix(deploy): change dockerfile to match other --- ARANGO_API/dockerfile | 6 +++--- BFF/Dockerfile | 6 +++--- deploy/docker/docker-compose.yml | 6 ++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/ARANGO_API/dockerfile b/ARANGO_API/dockerfile index 0feaa3c05..dfada514d 100644 --- a/ARANGO_API/dockerfile +++ b/ARANGO_API/dockerfile @@ -4,12 +4,12 @@ FROM golang:1.18.2-alpine3.16 AS build WORKDIR /build # We want to populate the module cache based on the go.{mod,sum} files. -COPY ARANGO_API/go.mod . -COPY ARANGO_API/go.sum . +COPY go.mod . +COPY go.sum . RUN go mod download -COPY ARANGO_API . +COPY . . # Build the Go app diff --git a/BFF/Dockerfile b/BFF/Dockerfile index f69e6b18d..703510c1b 100644 --- a/BFF/Dockerfile +++ b/BFF/Dockerfile @@ -4,12 +4,12 @@ FROM golang:1.18.2-alpine3.16 AS build WORKDIR /build # We want to populate the module cache based on the go.{mod,sum} files. -COPY BFF/go.mod . -COPY BFF/go.sum . +COPY go.mod . +COPY go.sum . RUN go mod download -COPY BFF . +COPY . . # Build the Go app diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index a718eafa4..b0dd399f7 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -77,8 +77,7 @@ services: arango_api: build: - context: ${CORE_DIR} - dockerfile: ${ARANGO_API_BUILD_DIR}/Dockerfile + context: ${CORE_DIR}/${ARANGO_API_BUILD_DIR} image: arango-api:${IMAGE_TAG} profiles: ["arango"] restart: always @@ -99,8 +98,7 @@ services: ogree-bff: build: - context: ${CORE_DIR} - dockerfile: ${BFF_BUILD_DIR}/Dockerfile + context: ${CORE_DIR}/${BFF_BUILD_DIR} image: ogree-bff:${IMAGE_TAG} profiles: ["arango"] restart: on-failure:10