From 18042c43f7dad7fba7de961f4b91175ce5bea585 Mon Sep 17 00:00:00 2001 From: Ronald Date: Sat, 9 Nov 2024 17:07:51 +0000 Subject: [PATCH] Adding this now The Go rewrite is almost complete and in some ways is more feature complete to what I want this to look like then the Python one. Just need to get some of the devices to measure temperature and humidity to talk to the Go API. --- go-api/.gitignore | 3 + go-api/docs/docs.go | 526 +++++++++++++++++++++++++++++++++++++++ go-api/docs/swagger.json | 498 ++++++++++++++++++++++++++++++++++++ go-api/docs/swagger.yaml | 324 ++++++++++++++++++++++++ go-api/go.mod | 59 +++++ go-api/go.sum | 167 +++++++++++++ go-api/main.go | 106 ++++++++ go-api/models/models.go | 52 ++++ go-api/routes.go | 333 +++++++++++++++++++++++++ 9 files changed, 2068 insertions(+) create mode 100644 go-api/.gitignore create mode 100644 go-api/docs/docs.go create mode 100644 go-api/docs/swagger.json create mode 100644 go-api/docs/swagger.yaml create mode 100644 go-api/go.mod create mode 100644 go-api/go.sum create mode 100644 go-api/main.go create mode 100644 go-api/models/models.go create mode 100644 go-api/routes.go diff --git a/go-api/.gitignore b/go-api/.gitignore new file mode 100644 index 0000000..2c4bec8 --- /dev/null +++ b/go-api/.gitignore @@ -0,0 +1,3 @@ +config.ini +go-api +sqlite.db diff --git a/go-api/docs/docs.go b/go-api/docs/docs.go new file mode 100644 index 0000000..ce2f613 --- /dev/null +++ b/go-api/docs/docs.go @@ -0,0 +1,526 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/humidity/add_humidity": { + "post": { + "description": "Add a humidity", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Humidity" + ], + "summary": "Add a humidity", + "parameters": [ + { + "description": "The humidity to create", + "name": "humidity", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.AddHumidity" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/models.Humidity" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/humidity/humidities": { + "get": { + "description": "Lists all the humidities in DTM for every room", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Humidity" + ], + "summary": "Get all humidities in DTM", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Humidity" + } + } + } + } + } + }, + "/rooms/add_room": { + "post": { + "description": "Create a room", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Create a room", + "parameters": [ + { + "description": "The room to create", + "name": "room", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.AddRoom" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/models.AddRoom" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/rooms/delete_room/{room_id}": { + "delete": { + "description": "Delete a room", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Delete a room", + "parameters": [ + { + "type": "string", + "description": "The ID of the room to be deleted", + "name": "room_id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/rooms/delete_room_by_name/{name}": { + "delete": { + "description": "Delete a room using it name", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Delete a room using its name", + "parameters": [ + { + "type": "string", + "description": "The name of the room to be deleted", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/rooms/get_room_by_name/{name}": { + "get": { + "description": "Get a room by its name", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Get a room by its name", + "parameters": [ + { + "type": "string", + "description": "The room to get based on its name", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Room" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/rooms/get_room_id_by_name/{name}": { + "get": { + "description": "Get the ID for a room based on its name", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Get the ID for a room based on its name", + "parameters": [ + { + "type": "string", + "description": "The name of the room to get the ID for", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "integer" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/rooms/rooms": { + "get": { + "description": "Lists all the rooms added to DTM", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Get all the rooms added to DTM", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Room" + } + } + } + } + } + }, + "/temperatures/add_temperature": { + "post": { + "description": "Add a temperature", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Temperatures" + ], + "summary": "Add a temperature", + "parameters": [ + { + "description": "The temperature to create", + "name": "temperature", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.AddTemperature" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/models.AddTemperature" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/temperatures/temperatures": { + "get": { + "description": "Lists all the temperatures in DTM for every room", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Temperatures" + ], + "summary": "Get all temperatures in DTM", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Temperature" + } + } + } + } + } + } + }, + "definitions": { + "models.AddHumidity": { + "type": "object", + "properties": { + "humidity": { + "type": "number" + }, + "room_name": { + "type": "string" + } + } + }, + "models.AddRoom": { + "type": "object", + "properties": { + "Name": { + "type": "string" + } + } + }, + "models.AddTemperature": { + "type": "object", + "properties": { + "room_name": { + "type": "string" + }, + "temperature": { + "type": "number" + } + } + }, + "models.Error": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "models.Humidity": { + "type": "object", + "properties": { + "humidity": { + "type": "number" + }, + "room_id": { + "type": "integer" + }, + "time": { + "type": "string" + } + } + }, + "models.Room": { + "type": "object", + "properties": { + "humidity": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Humidity" + } + }, + "name": { + "type": "string" + }, + "temperature": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Temperature" + } + } + } + }, + "models.Temperature": { + "type": "object", + "properties": { + "room_id": { + "type": "integer" + }, + "temperature": { + "type": "number" + }, + "time": { + "type": "string" + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "", + Host: "", + BasePath: "/api/v1", + Schemes: []string{}, + Title: "", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/go-api/docs/swagger.json b/go-api/docs/swagger.json new file mode 100644 index 0000000..ea94db3 --- /dev/null +++ b/go-api/docs/swagger.json @@ -0,0 +1,498 @@ +{ + "swagger": "2.0", + "info": { + "contact": {} + }, + "basePath": "/api/v1", + "paths": { + "/humidity/add_humidity": { + "post": { + "description": "Add a humidity", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Humidity" + ], + "summary": "Add a humidity", + "parameters": [ + { + "description": "The humidity to create", + "name": "humidity", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.AddHumidity" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/models.Humidity" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/humidity/humidities": { + "get": { + "description": "Lists all the humidities in DTM for every room", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Humidity" + ], + "summary": "Get all humidities in DTM", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Humidity" + } + } + } + } + } + }, + "/rooms/add_room": { + "post": { + "description": "Create a room", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Create a room", + "parameters": [ + { + "description": "The room to create", + "name": "room", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.AddRoom" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/models.AddRoom" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/rooms/delete_room/{room_id}": { + "delete": { + "description": "Delete a room", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Delete a room", + "parameters": [ + { + "type": "string", + "description": "The ID of the room to be deleted", + "name": "room_id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/rooms/delete_room_by_name/{name}": { + "delete": { + "description": "Delete a room using it name", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Delete a room using its name", + "parameters": [ + { + "type": "string", + "description": "The name of the room to be deleted", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/rooms/get_room_by_name/{name}": { + "get": { + "description": "Get a room by its name", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Get a room by its name", + "parameters": [ + { + "type": "string", + "description": "The room to get based on its name", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Room" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/rooms/get_room_id_by_name/{name}": { + "get": { + "description": "Get the ID for a room based on its name", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Get the ID for a room based on its name", + "parameters": [ + { + "type": "string", + "description": "The name of the room to get the ID for", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "integer" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/rooms/rooms": { + "get": { + "description": "Lists all the rooms added to DTM", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rooms" + ], + "summary": "Get all the rooms added to DTM", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Room" + } + } + } + } + } + }, + "/temperatures/add_temperature": { + "post": { + "description": "Add a temperature", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Temperatures" + ], + "summary": "Add a temperature", + "parameters": [ + { + "description": "The temperature to create", + "name": "temperature", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.AddTemperature" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/models.AddTemperature" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.Error" + } + }, + "409": { + "description": "Conflict", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/temperatures/temperatures": { + "get": { + "description": "Lists all the temperatures in DTM for every room", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Temperatures" + ], + "summary": "Get all temperatures in DTM", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Temperature" + } + } + } + } + } + } + }, + "definitions": { + "models.AddHumidity": { + "type": "object", + "properties": { + "humidity": { + "type": "number" + }, + "room_name": { + "type": "string" + } + } + }, + "models.AddRoom": { + "type": "object", + "properties": { + "Name": { + "type": "string" + } + } + }, + "models.AddTemperature": { + "type": "object", + "properties": { + "room_name": { + "type": "string" + }, + "temperature": { + "type": "number" + } + } + }, + "models.Error": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "models.Humidity": { + "type": "object", + "properties": { + "humidity": { + "type": "number" + }, + "room_id": { + "type": "integer" + }, + "time": { + "type": "string" + } + } + }, + "models.Room": { + "type": "object", + "properties": { + "humidity": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Humidity" + } + }, + "name": { + "type": "string" + }, + "temperature": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Temperature" + } + } + } + }, + "models.Temperature": { + "type": "object", + "properties": { + "room_id": { + "type": "integer" + }, + "temperature": { + "type": "number" + }, + "time": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/go-api/docs/swagger.yaml b/go-api/docs/swagger.yaml new file mode 100644 index 0000000..8b91265 --- /dev/null +++ b/go-api/docs/swagger.yaml @@ -0,0 +1,324 @@ +basePath: /api/v1 +definitions: + models.AddHumidity: + properties: + humidity: + type: number + room_name: + type: string + type: object + models.AddRoom: + properties: + Name: + type: string + type: object + models.AddTemperature: + properties: + room_name: + type: string + temperature: + type: number + type: object + models.Error: + properties: + error: + type: string + status: + type: string + type: object + models.Humidity: + properties: + humidity: + type: number + room_id: + type: integer + time: + type: string + type: object + models.Room: + properties: + humidity: + items: + $ref: '#/definitions/models.Humidity' + type: array + name: + type: string + temperature: + items: + $ref: '#/definitions/models.Temperature' + type: array + type: object + models.Temperature: + properties: + room_id: + type: integer + temperature: + type: number + time: + type: string + type: object +info: + contact: {} +paths: + /humidity/add_humidity: + post: + consumes: + - application/json + description: Add a humidity + parameters: + - description: The humidity to create + in: body + name: humidity + required: true + schema: + $ref: '#/definitions/models.AddHumidity' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/models.Humidity' + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + "409": + description: Conflict + schema: + $ref: '#/definitions/models.Error' + summary: Add a humidity + tags: + - Humidity + /humidity/humidities: + get: + consumes: + - application/json + description: Lists all the humidities in DTM for every room + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Humidity' + type: array + summary: Get all humidities in DTM + tags: + - Humidity + /rooms/add_room: + post: + consumes: + - application/json + description: Create a room + parameters: + - description: The room to create + in: body + name: room + required: true + schema: + $ref: '#/definitions/models.AddRoom' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/models.AddRoom' + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + "409": + description: Conflict + schema: + $ref: '#/definitions/models.Error' + summary: Create a room + tags: + - Rooms + /rooms/delete_room/{room_id}: + delete: + consumes: + - application/json + description: Delete a room + parameters: + - description: The ID of the room to be deleted + in: path + name: room_id + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + summary: Delete a room + tags: + - Rooms + /rooms/delete_room_by_name/{name}: + delete: + consumes: + - application/json + description: Delete a room using it name + parameters: + - description: The name of the room to be deleted + in: path + name: name + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + summary: Delete a room using its name + tags: + - Rooms + /rooms/get_room_by_name/{name}: + get: + consumes: + - application/json + description: Get a room by its name + parameters: + - description: The room to get based on its name + in: path + name: name + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.Room' + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + summary: Get a room by its name + tags: + - Rooms + /rooms/get_room_id_by_name/{name}: + get: + consumes: + - application/json + description: Get the ID for a room based on its name + parameters: + - description: The name of the room to get the ID for + in: path + name: name + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: integer + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + summary: Get the ID for a room based on its name + tags: + - Rooms + /rooms/rooms: + get: + consumes: + - application/json + description: Lists all the rooms added to DTM + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Room' + type: array + summary: Get all the rooms added to DTM + tags: + - Rooms + /temperatures/add_temperature: + post: + consumes: + - application/json + description: Add a temperature + parameters: + - description: The temperature to create + in: body + name: temperature + required: true + schema: + $ref: '#/definitions/models.AddTemperature' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/models.AddTemperature' + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + "409": + description: Conflict + schema: + $ref: '#/definitions/models.Error' + summary: Add a temperature + tags: + - Temperatures + /temperatures/temperatures: + get: + consumes: + - application/json + description: Lists all the temperatures in DTM for every room + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Temperature' + type: array + summary: Get all temperatures in DTM + tags: + - Temperatures +swagger: "2.0" diff --git a/go-api/go.mod b/go-api/go.mod new file mode 100644 index 0000000..0feb70c --- /dev/null +++ b/go-api/go.mod @@ -0,0 +1,59 @@ +module digital_temperature_monitor + +go 1.23.0 + +require ( + github.com/gin-gonic/gin v1.10.0 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + gopkg.in/ini.v1 v1.67.0 + gorm.io/driver/postgres v1.5.9 + gorm.io/driver/sqlite v1.5.6 + gorm.io/gorm v1.25.12 +) + +require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/bytedance/sonic v1.12.2 // indirect + github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // 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.22.0 // indirect + github.com/goccy/go-json v0.10.3 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.6.0 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // 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.8 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/swaggo/swag v1.16.3 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.10.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.24.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go-api/go.sum b/go-api/go.sum new file mode 100644 index 0000000..29c25a2 --- /dev/null +++ b/go-api/go.sum @@ -0,0 +1,167 @@ +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg= +github.com/bytedance/sonic v1.12.2/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= +github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= +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.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +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.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= +github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= +github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +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/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +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/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/stretchr/objx v0.1.0/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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= +github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= +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.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8= +golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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= +gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8= +gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= +gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE= +gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/go-api/main.go b/go-api/main.go new file mode 100644 index 0000000..cff5f42 --- /dev/null +++ b/go-api/main.go @@ -0,0 +1,106 @@ +package main + +import ( + docs "digital_temperature_monitor/docs" + "fmt" + "log" + "strings" + + "github.com/gin-gonic/gin" + swaggerfiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" + "gopkg.in/ini.v1" + + "digital_temperature_monitor/models" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +var DB *gorm.DB + +// @BasePath /api/v1 + +func main() { + cfg, err := ini.Load("config.ini") + if err != nil { + log.Fatal("Fail to read file: ", err) + } + + // Classic read of values, default section can be represented as empty string + fmt.Println("App Mode: ", cfg.Section("").Key("app_mode").String()) + fmt.Println("Database Type: ", cfg.Section("database").Key("type").String()) + + if strings.ToLower(cfg.Section("database").Key("type").String()) == "postgres" { + fmt.Println("Database Host: ", cfg.Section("database").Key("host").String()) + fmt.Println("Database Port: ", cfg.Section("database").Key("port").String()) + fmt.Println("Database Username:", cfg.Section("database").Key("username").String()) + fmt.Println("Database Name: ", cfg.Section("database").Key("db_name").String()) + + databaseConnectString := fmt.Sprintf( + "host=%s port=%s user=%s dbname=%s password=%s sslmode=disable", + cfg.Section("database").Key("host"), + cfg.Section("database").Key("port"), + cfg.Section("database").Key("user"), + cfg.Section("database").Key("db_name"), + cfg.Section("database").Key("password"), + ) + + log.Println(databaseConnectString) + DB, err = gorm.Open(postgres.Open(databaseConnectString), &gorm.Config{TranslateError: true}) + if err != nil { + log.Fatal("Failed to connect to PostgreSQL DB") + } + } else if strings.ToLower(cfg.Section("database").Key("type").String()) == "sqlite" { + sqlite_path := cfg.Section("database").Key("path").String() + fmt.Println("sqlite DB Path: ", sqlite_path) + + DB, err = gorm.Open(sqlite.Open(sqlite_path), &gorm.Config{TranslateError: true}) + if err != nil { + log.Fatal("Failed to open sqlite DB") + } + } + + log.Println("Successfully connected to database") + + err = DB.AutoMigrate(&models.Temperature{}) + if err != nil { + log.Fatal("failed to migrate temperature schema") + } + err = DB.AutoMigrate(&models.Room{}) + if err != nil { + log.Fatal("Failed to migrate room schema") + } + + r := gin.Default() + docs.SwaggerInfo.BasePath = "/api/v1" + v1 := r.Group("/api/v1") + { + rooms := v1.Group("/rooms") + { + rooms.GET("/rooms", GetRooms) + rooms.GET("/get_room_by_name/:name", GetRoomByName) + rooms.GET("/get_room_id_by_name/:name", GetRoomIDByName) + rooms.POST("/add_room", AddRoom) + rooms.DELETE("/delete_room/:room_id", DeleteRoom) + rooms.DELETE("/delete_room_by_name/:name", DeleteRoomByName) + } + temperature := v1.Group("/temperature") + { + temperature.GET("/temperatures", GetTemperatures) + temperature.POST("/add_temperature", AddTemperature) + } + humidity := v1.Group("/humidity") + { + humidity.GET("/humidities", GetHumidities) + humidity.POST("/add_humidity", AddHumidity) + } + } + + r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) + err = r.Run(":8080") + if err != nil { + log.Fatal("Failed to start API") + } +} diff --git a/go-api/models/models.go b/go-api/models/models.go new file mode 100644 index 0000000..7ab563b --- /dev/null +++ b/go-api/models/models.go @@ -0,0 +1,52 @@ +package models + +import ( + "time" + + "gorm.io/gorm" +) + +type Temperature struct { + gorm.Model `json:"-"` + ID uint `json:"-" gorm:"primary_key"` + Time time.Time `json:"time" gorm:"autoCreateTime"` + Temperature float64 `json:"temperature"` + RoomID int `json:"room_id"` + Room Room `json:"-" gorm:"foreignKey:ID;references:RoomID"` +} + +type Humidity struct { + gorm.Model `json:"-"` + ID uint `json:"-" gorm:"primary_key"` + Time time.Time `json:"time" gorm:"autoCreateTime"` + Humidity float64 `json:"humidity"` + RoomID int `json:"room_id"` + Room Room `json:"-" gorm:"foreignKey:ID;references:RoomID"` +} + +type Room struct { + gorm.Model `json:"-"` + ID int `json:"-" gorm:"primary_key;autoIncrement"` + Name string `json:"name" gorm:"unique"` + Temperatures []Temperature `json:"temperature" gorm:"foreignKey:ID"` + Humidity []Humidity `json:"humidity" gorm:"foreignKey:ID"` +} + +type AddRoom struct { + Name string `json:"Name"` +} + +type AddTemperature struct { + RoomName string `json:"room_name"` + Temperature float64 `json:"temperature"` +} + +type AddHumidity struct { + RoomName string `json:"room_name"` + Humidity float64 `json:"humidity"` +} + +type Error struct { + Status string `json:"status"` + Error string `json:"error"` +} diff --git a/go-api/routes.go b/go-api/routes.go new file mode 100644 index 0000000..569877e --- /dev/null +++ b/go-api/routes.go @@ -0,0 +1,333 @@ +package main + +import ( + "digital_temperature_monitor/models" + "errors" + "net/http" + + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +// @Summary Get all the rooms added to DTM +// @Description Lists all the rooms added to DTM +// @Tags Rooms +// @Accept json +// @Produce json +// @Success 200 {object} []models.Room +// @Router /rooms/rooms [get] +func GetRooms(c *gin.Context) { + var rooms []models.Room + DB.Find(&rooms) + c.JSON(http.StatusOK, rooms) +} + +// @Summary Get a room by its name +// @Description Get a room by its name +// @Tags Rooms +// @Accept json +// @Produce json +// @Param name path string true "The room to get based on its name" +// @Success 200 {object} models.Room +// @Failure 400 {object} models.Error +// @Failure 404 {object} models.Error +// @Router /rooms/get_room_by_name/{name} [get] +func GetRoomByName(c *gin.Context) { + var room models.Room + name := c.Param("name") + + if err := DB.Where("name = ?", name).First(&room).Error; err == gorm.ErrRecordNotFound { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": "record not found", + }) + return + } else if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": err.Error, + }) + } + + c.JSON(http.StatusOK, room) +} + +// @Summary Get the ID for a room based on its name +// @Description Get the ID for a room based on its name +// @Tags Rooms +// @Accept json +// @Produce json +// @Param name path string true "The name of the room to get the ID for" +// @Success 200 {object} int +// @Failure 400 {object} models.Error +// @Failure 404 {object} models.Error +// @Router /rooms/get_room_id_by_name/{name} [get] +func GetRoomIDByName(c *gin.Context) { + var room models.Room + name := c.Param("name") + + if err := DB.Where("name = ?", name).First(&room).Error; err == gorm.ErrRecordNotFound { + c.JSON(http.StatusNotFound, gin.H{ + "Status": "failed", + "error": "record not found", + }) + return + } else if err != nil { + c.JSON(http.StatusNotFound, gin.H{ + "Status": "failed", + "Error": err.Error, + }) + + return + } + + c.JSON(http.StatusOK, room.ID) +} + +// AddRoom godoc +// @Summary Create a room +// @Description Create a room +// @Tags Rooms +// @Accept json +// @Produce json +// @Param room body models.AddRoom true "The room to create" +// @Success 201 {object} models.AddRoom +// @Failure 400 {object} models.Error +// @Failure 409 {object} models.Error +// @Router /rooms/add_room [post] +func AddRoom(c *gin.Context) { + var input models.AddRoom + if err := c.ShouldBindJSON(&input); err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": err.Error(), + }) + return + } + + room := models.Room{Name: input.Name} + result := DB.Create(&room) + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + c.JSON(http.StatusConflict, gin.H{ + "status": "failure", + "error": "room already exists in dtm", + }) + return + } else if result.Error != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "failure", + "error": result.Error, + }) + return + } + + c.JSON(http.StatusCreated, input) +} + +// DeleteRoom godoc +// @Summary Delete a room +// @Description Delete a room +// @Tags Rooms +// @Accept json +// @Produce json +// @Param room_id path string true "The ID of the room to be deleted" +// @Success 204 +// @Failure 400 {object} models.Error +// @Failure 404 {object} models.Error +// @Router /rooms/delete_room/{room_id} [delete] +func DeleteRoom(c *gin.Context) { + var room models.Room + roomID := c.Param("room_id") + if err := DB.Where("ID = ?", roomID).Delete(&room).Error; err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": err.Error, + }) + return + } else if DB.RowsAffected < 1 { + c.JSON(http.StatusNotFound, gin.H{ + "status": "error", + "error": "record not found", + }) + return + } + + c.Status(http.StatusNoContent) +} + +// DeleteRoomByName godoc +// @Summary Delete a room using its name +// @Description Delete a room using it name +// @Tags Rooms +// @Accept json +// @Produce json +// @Param name path string true "The name of the room to be deleted" +// @Success 204 +// @Failure 400 {object} models.Error +// @Failure 404 {object} models.Error +// @Router /rooms/delete_room_by_name/{name} [delete] +func DeleteRoomByName(c *gin.Context) { + name := c.Param("name") + var room models.Room + if result := DB.Where("name = ?", name).Unscoped().Delete(&room); result.Error != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": result.Error, + }) + return + } else if result.RowsAffected < 1 { + c.JSON(http.StatusNotFound, gin.H{ + "status": "error", + "error": "record not found", + }) + return + } + + c.Status(http.StatusNoContent) +} + +// @Summary Get all temperatures in DTM +// @Description Lists all the temperatures in DTM for every room +// @Tags Temperatures +// @Accept json +// @Produce json +// @Success 200 {object} []models.Temperature +// @Router /temperatures/temperatures [get] +func GetTemperatures(c *gin.Context) { + var temperatures []models.Temperature + DB.Find(&temperatures) + c.JSON(http.StatusOK, temperatures) +} + +// AddTemperature godoc +// @Summary Add a temperature +// @Description Add a temperature +// @Tags Temperatures +// @Accept json +// @Produce json +// @Param temperature body models.AddTemperature true "The temperature to create" +// @Success 201 {object} models.AddTemperature +// @Failure 400 {object} models.Error +// @Failure 404 {object} models.Error +// @Failure 409 {object} models.Error +// @Router /temperatures/add_temperature [post] +func AddTemperature(c *gin.Context) { + var addTemperature models.AddTemperature + if err := c.ShouldBindJSON(&addTemperature); err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": err.Error, + }) + return + } + + var temperature models.Temperature + temperature.Temperature = addTemperature.Temperature + + var room models.Room + name := addTemperature.RoomName + if err := DB.Where("name = ?", name).First(&room).Error; err == gorm.ErrRecordNotFound { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": "record not found", + }) + return + } else if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": err.Error, + }) + } + + temperature.RoomID = room.ID + + result := DB.Create(&temperature) + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + c.JSON(http.StatusConflict, gin.H{ + "status": "failure", + "error": "room already exists in dtm", + }) + return + } else if result.Error != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "failure", + "error": result.Error, + }) + return + } + + c.JSON(http.StatusCreated, temperature) +} + +// @Summary Get all humidities in DTM +// @Description Lists all the humidities in DTM for every room +// @Tags Humidity +// @Accept json +// @Produce json +// @Success 200 {object} []models.Humidity +// @Router /humidity/humidities [get] +func GetHumidities(c *gin.Context) { + var humidities []models.Humidity + DB.Find(&humidities) + c.JSON(http.StatusOK, humidities) +} + +// AddHumidity godoc +// @Summary Add a humidity +// @Description Add a humidity +// @Tags Humidity +// @Accept json +// @Produce json +// @Param humidity body models.AddHumidity true "The humidity to create" +// @Success 201 {object} models.Humidity +// @Failure 400 {object} models.Error +// @Failure 404 {object} models.Error +// @Failure 409 {object} models.Error +// @Router /humidity/add_humidity [post] +func AddHumidity(c *gin.Context) { + var addHumidity models.AddHumidity + if err := c.ShouldBindJSON(&addHumidity); err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": err.Error, + }) + return + } + + var humidity models.Humidity + humidity.Humidity = addHumidity.Humidity + + var room models.Room + name := addHumidity.RoomName + if err := DB.Where("name = ?", name).First(&room).Error; err == gorm.ErrRecordNotFound { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": "record not found", + }) + return + } else if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "error", + "error": err.Error, + }) + } + + humidity.RoomID = room.ID + + result := DB.Create(&humidity) + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + c.JSON(http.StatusConflict, gin.H{ + "status": "failure", + "error": "room already exists in dtm", + }) + return + } else if result.Error != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "failure", + "error": result.Error, + }) + return + } + + c.JSON(http.StatusCreated, humidity) +}