Author: Paolo Lulli <paolo@lulli.net>
Add endpoint search for Positions
client/.gitignore | 2 client/.idea/vcs.xml | 1 schema/schema.cql | 9 +++ server/db/position.go | 12 ++++ server/docs/docs.go | 112 ++++++++++++++++++++++++++++++++++++++ server/docs/swagger.json | 112 ++++++++++++++++++++++++++++++++++++++ server/docs/swagger.yaml | 74 +++++++++++++++++++++++++ server/model/models.go | 7 ++ server/rest/rest-position.go | 81 +++++++++++++++++++++++++++
diff --git a/client/.gitignore b/client/.gitignore index 5add2221c9996f92e9334fbeb298cecce7f69742..f60ffd693d430f084275685ca9c7d5c11c058e83 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -1,3 +1,3 @@ yats .dqt -.idea +.idea/ diff --git a/client/.idea/vcs.xml b/client/.idea/vcs.xml index 35eb1ddfbbc029bcab630581847471d7f238ec53..62bd7a01e9c46011ff345da2389b38fd0fa6d41a 100644 --- a/client/.idea/vcs.xml +++ b/client/.idea/vcs.xml @@ -2,5 +2,6 @@ <project version="4"> <component name="VcsDirectoryMappings"> <mapping directory="" vcs="Git" /> + <mapping directory="$PROJECT_DIR$/.." vcs="Git" /> </component> </project> \ No newline at end of file diff --git a/schema/schema.cql b/schema/schema.cql index fad6b290beeea10d17dea832703fb5d4e851d1bf..4f958d807e5a243e397a8972e0feedb69e1768e9 100644 --- a/schema/schema.cql +++ b/schema/schema.cql @@ -32,6 +32,15 @@ lon double, name text, PRIMARY KEY (id_client,ptime) ); +CREATE TABLE sources ( + id_client text, + name text, + type text, + app text, + description text, + PRIMARY KEY (id_client,app,type,name) +); +CREATE INDEX ON sources(id_client); CREATE TABLE location ( hash text, diff --git a/server/db/position.go b/server/db/position.go index 128b7e40faf6316a3144d6f8c5a35c10cd49610f..c2047a8749f06f5118f68c7f20a7f573123f7460 100644 --- a/server/db/position.go +++ b/server/db/position.go @@ -27,3 +27,15 @@ q := fmt.Sprintf("insert into position ( id_client, ptime, lat, lon, name) values ('%s','%s',%f,%f,'%s');", idClient, string(timeAsBytes), lat, lon, positionName) fmt.Printf("q=%s", q) Session.Query(q).Exec() } +func CanReadSourcePosition(idClient string, sourceApp string) bool { + m := map[string]interface{}{} + + q := fmt.Sprintf(" SELECT name,app,type from sources where id_client='%s' and app='%s' and type='position';", idClient, sourceApp) + fmt.Println(q) + iter := Session.Query(q).Iter() + + for iter.MapScan(m) { + return true + } + return false +} diff --git a/server/docs/docs.go b/server/docs/docs.go index 92cd9d1b1212b0b1011b8366718c7646e5766d9d..ac74a0e0a98edf161091a590a93f7d6afae01027 100644 --- a/server/docs/docs.go +++ b/server/docs/docs.go @@ -319,6 +319,95 @@ } } } } + }, + "/position/search": { + "post": { + "description": "retrieve positions in the specified time window", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Positions" + ], + "summary": "Get the positions From ... and To when present", + "parameters": [ + { + "type": "string", + "description": "clientCN", + "name": "X-SSL-Client-CN", + "in": "header", + "required": true + }, + { + "description": "Position query filters", + "name": "position", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.PositionSearchRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + } + } + } + }, + "/position/{from}": { + "get": { + "description": "retrieve positions from timestamp {from}", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Positions" + ], + "summary": "Get the positions from timestamp {from}", + "parameters": [ + { + "type": "string", + "description": "clientCN", + "name": "X-SSL-Client-CN", + "in": "header", + "required": true + }, + { + "description": "Event query filters", + "name": "position", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.PositionSearchRequest" + } + }, + { + "type": "string", + "description": "Starting from timestamp :from", + "name": "from", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + } + } + } } }, "definitions": { @@ -345,6 +434,9 @@ }, "id_client": { "type": "string" }, + "source": { + "type": "string" + }, "to": { "type": "integer" } @@ -379,6 +471,9 @@ }, "name": { "type": "string" }, + "source": { + "type": "string" + }, "to": { "type": "integer" } @@ -402,6 +497,23 @@ "name": { "type": "string" }, "ptime": { + "type": "integer" + } + } + }, + "model.PositionSearchRequest": { + "type": "object", + "properties": { + "from": { + "type": "integer" + }, + "id_client": { + "type": "string" + }, + "source": { + "type": "string" + }, + "to": { "type": "integer" } } diff --git a/server/docs/swagger.json b/server/docs/swagger.json index 7879f76ac280dd8e848914e957e24f8e92b67642..7fa7784282a08cc301e1e9f2eaca8a0f110defb0 100755 --- a/server/docs/swagger.json +++ b/server/docs/swagger.json @@ -312,6 +312,95 @@ } } } } + }, + "/position/search": { + "post": { + "description": "retrieve positions in the specified time window", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Positions" + ], + "summary": "Get the positions From ... and To when present", + "parameters": [ + { + "type": "string", + "description": "clientCN", + "name": "X-SSL-Client-CN", + "in": "header", + "required": true + }, + { + "description": "Position query filters", + "name": "position", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.PositionSearchRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + } + } + } + }, + "/position/{from}": { + "get": { + "description": "retrieve positions from timestamp {from}", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Positions" + ], + "summary": "Get the positions from timestamp {from}", + "parameters": [ + { + "type": "string", + "description": "clientCN", + "name": "X-SSL-Client-CN", + "in": "header", + "required": true + }, + { + "description": "Event query filters", + "name": "position", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.PositionSearchRequest" + } + }, + { + "type": "string", + "description": "Starting from timestamp :from", + "name": "from", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + } + } + } } }, "definitions": { @@ -338,6 +427,9 @@ }, "id_client": { "type": "string" }, + "source": { + "type": "string" + }, "to": { "type": "integer" } @@ -372,6 +464,9 @@ }, "name": { "type": "string" }, + "source": { + "type": "string" + }, "to": { "type": "integer" } @@ -395,6 +490,23 @@ "name": { "type": "string" }, "ptime": { + "type": "integer" + } + } + }, + "model.PositionSearchRequest": { + "type": "object", + "properties": { + "from": { + "type": "integer" + }, + "id_client": { + "type": "string" + }, + "source": { + "type": "string" + }, + "to": { "type": "integer" } } diff --git a/server/docs/swagger.yaml b/server/docs/swagger.yaml index 880f7eb10c381fa3b2da76bafe98c4d2f30cc568..5b73ff2eb0b1523b49ed64a2e29a08c1bea95e68 100755 --- a/server/docs/swagger.yaml +++ b/server/docs/swagger.yaml @@ -15,6 +15,8 @@ from: type: integer id_client: type: string + source: + type: string to: type: integer type: object @@ -36,6 +38,8 @@ type: integer id_client: type: string name: + type: string + source: type: string to: type: integer @@ -53,6 +57,17 @@ type: number name: type: string ptime: + type: integer + type: object + model.PositionSearchRequest: + properties: + from: + type: integer + id_client: + type: string + source: + type: string + to: type: integer type: object externalDocs: @@ -265,6 +280,65 @@ description: Accepted schema: type: string summary: write position to db + tags: + - Positions + /position/{from}: + get: + consumes: + - application/json + description: retrieve positions from timestamp {from} + parameters: + - description: clientCN + in: header + name: X-SSL-Client-CN + required: true + type: string + - description: Event query filters + in: body + name: position + required: true + schema: + $ref: '#/definitions/model.PositionSearchRequest' + - description: Starting from timestamp :from + in: path + name: from + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + summary: Get the positions from timestamp {from} + tags: + - Positions + /position/search: + post: + consumes: + - application/json + description: retrieve positions in the specified time window + parameters: + - description: clientCN + in: header + name: X-SSL-Client-CN + required: true + type: string + - description: Position query filters + in: body + name: position + required: true + schema: + $ref: '#/definitions/model.PositionSearchRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + summary: Get the positions From ... and To when present tags: - Positions swagger: "2.0" diff --git a/server/model/models.go b/server/model/models.go index c35470218a7dfa100a08f62065f9eabbe9fa5740..20fa899887561a9bd028472d00521a26fa87d1e2 100644 --- a/server/model/models.go +++ b/server/model/models.go @@ -57,3 +57,10 @@ To int64 `json:"to" parquet:"name=mtime, type=INT64, convertedtype=TIMESTAMP_MILLIS"` IdClient string `json:"id_client" parquet:"name=id_client, type=BYTE_ARRAY, convertedtype=UTF8"` SourceApplication string `json:"source" parquet:"name=source_application, type=BYTE_ARRAY, convertedtype=UTF8"` } + +type PositionSearchRequest struct { + From int64 `json:"from" parquet:"name=mtime, type=INT64, convertedtype=TIMESTAMP_MILLIS"` + To int64 `json:"to" parquet:"name=mtime, type=INT64, convertedtype=TIMESTAMP_MILLIS"` + IdClient string `json:"id_client" parquet:"name=id_client, type=BYTE_ARRAY, convertedtype=UTF8"` + SourceApplication string `json:"source" parquet:"name=source_application, type=BYTE_ARRAY, convertedtype=UTF8"` +} diff --git a/server/rest/rest-position.go b/server/rest/rest-position.go index 4177d4a544e12b67f269b6499ca9f4ce48b95938..762e083964b1a9f8a7af4a120c1da8d93f5ff017 100644 --- a/server/rest/rest-position.go +++ b/server/rest/rest-position.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/gin-gonic/gin" "net/http" + "strconv" "time" "yats-server/config" "yats-server/db" @@ -42,3 +43,83 @@ } c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK"}) } } + +// SearchPositions godoc +// @Param X-SSL-Client-CN header string true "clientCN" +// @Summary Get the positions From ... and To when present +// @Schemes +// @Description retrieve positions in the specified time window +// @Tags Positions +// @Accept json +// @Param position body model.PositionSearchRequest true "Position query filters" +// @Produce json +// @Success 200 {string} SearchPositions +// @Router /position/search [post] +func SearchPositions(cfg config.Configuration) gin.HandlerFunc { + return func(c *gin.Context) { + var position model.PositionSearchRequest + + if err := c.BindJSON(&position); err != nil { + c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"}) + return + } + + clientCN := GetClientCN(c, cfg) + fmt.Printf("Client ID: %s\n ", clientCN) + + if position.SourceApplication != "" { + if !db.CanReadSourcePosition(clientCN, position.SourceApplication) { + c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"}) + } + clientCN = position.SourceApplication + } + + var eventsPack []model.EventModel + if position.To == 0 { + unixTimeUTC := time.Unix(position.From, 0) + timeAsBytes, _ := unixTimeUTC.UTC().MarshalText() + eventsPack = db.EventsFrom(db.Session, clientCN, string(timeAsBytes), 100) + } else if position.From != 0 { + fromUnixTimeUTC := time.Unix(position.From, 0) + toUnixTimeUTC := time.Unix(position.To, 0) + fromInBytes, _ := fromUnixTimeUTC.UTC().MarshalText() + toInBytes, _ := toUnixTimeUTC.UTC().MarshalText() + eventsPack = db.EventsBetween(db.Session, clientCN, string(fromInBytes), string(toInBytes), 100) + } + c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK", "content": eventsPack}) + } +} + +// GetPositionsFrom godoc +// @Param X-SSL-Client-CN header string true "clientCN" +// @Summary Get the positions from timestamp {from} +// @Schemes +// @Description retrieve positions from timestamp {from} +// @Tags Positions +// @Accept json +// @Param position body model.PositionSearchRequest true "Event query filters" +// @Produce json +// @Success 200 {string} SearchPositions +// @Router /position/{from} [get] +// @Param from path string true "Starting from timestamp :from" +func GetPositionsFrom(cfg config.Configuration) gin.HandlerFunc { + return func(c *gin.Context) { + + fromParam := c.Param("from") + fromParamInt64, err := strconv.ParseInt(fromParam, 10, 64) + if err != nil { + c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "-1"}) + } + + clientCN := GetClientCN(c, cfg) + fmt.Printf("Client ID: %s\n ", clientCN) + + var eventsPack []model.EventModel + + unixTimeUTC := time.Unix(fromParamInt64, 0) + timeAsBytes, _ := unixTimeUTC.UTC().MarshalText() + eventsPack = db.EventsFrom(db.Session, clientCN, string(timeAsBytes), 100) + + c.IndentedJSON(http.StatusAccepted, gin.H{"ret": "OK", "content": eventsPack}) + } +}