From 7fee03c4163cdd1724d1f9ff76398ac4431c18e6 Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 28 Apr 2024 12:32:51 -0700 Subject: [PATCH 1/2] Minor adjustments and getting discord webhooks handler updated --- .gitignore | 3 - docs/docs.go | 539 ++++++++++++++++--------- docs/swagger.json | 539 ++++++++++++++++--------- docs/swagger.yaml | 385 +++++++++++------- internal/domain/dto.go | 6 +- internal/domain/entity.go | 2 - internal/domain/responses.go | 2 +- internal/handler/v1/articles.go | 10 +- internal/handler/v1/discordwebhooks.go | 283 +++++++------ internal/handler/v1/handler.go | 16 +- internal/handler/v1/root_test.go | 1 - internal/services/dtoconv.go | 18 + 12 files changed, 1160 insertions(+), 644 deletions(-) delete mode 100644 internal/handler/v1/root_test.go diff --git a/.gitignore b/.gitignore index 75d8d2c..efcc85d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,6 @@ __debug_bin server .vscode -# hide the swagger files in the repo -docs/ - # Binaries for programs and plugins *.exe *.exe~ diff --git a/docs/docs.go b/docs/docs.go index 7cc13e7..2ee6122 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -37,7 +37,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.ArticlesListResults" + "$ref": "#/definitions/domain.ArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -55,7 +67,7 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "Source ID UUID", + "description": "source id", "name": "id", "in": "query", "required": true @@ -71,7 +83,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.ArticlesListResults" + "$ref": "#/definitions/domain.ArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -89,7 +113,7 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "uuid", + "description": "int", "name": "ID", "in": "path", "required": true @@ -99,7 +123,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.ArticleGetResults" + "$ref": "#/definitions/domain.ArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -117,7 +153,7 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "uuid", + "description": "int", "name": "ID", "in": "path", "required": true @@ -127,7 +163,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.ArticleDetailsResult" + "$ref": "#/definitions/domain.ArticleDetailedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -142,8 +190,27 @@ const docTemplate = `{ "Discord", "Webhook" ], - "summary": "Returns the top 100 entries from the queue to be processed.", - "responses": {} + "summary": "Returns the top 100", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/discord/webhooks/by/serverAndChannel": { @@ -176,7 +243,19 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.ListDiscordWebhooks" + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -212,7 +291,26 @@ const docTemplate = `{ "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/discord/webhooks/{ID}": { @@ -231,7 +329,26 @@ const docTemplate = `{ "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/discord/webhooks/{ID}/disable": { @@ -243,14 +360,33 @@ const docTemplate = `{ "summary": "Disables a Webhook from being used.", "parameters": [ { - "type": "string", + "type": "integer", "description": "id", "name": "id", "in": "path", "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/discord/webhooks/{ID}/enable": { @@ -262,7 +398,7 @@ const docTemplate = `{ "summary": "Enables a source to continue processing.", "parameters": [ { - "type": "string", + "type": "integer", "description": "id", "name": "id", "in": "path", @@ -284,7 +420,7 @@ const docTemplate = `{ "summary": "Returns the top 100 entries from the queue to be processed.", "parameters": [ { - "type": "string", + "type": "integer", "description": "id", "name": "id", "in": "path", @@ -295,27 +431,22 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.GetDiscordWebhook" + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } - }, - "patch": { - "tags": [ - "Discord", - "Webhook" - ], - "summary": "Updates a valid discord webhook ID based on the body given.", - "parameters": [ - { - "type": "string", - "description": "id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": {} } }, "/queue/discord/webhooks": { @@ -331,12 +462,33 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListDiscordWebHooksQueueResults" + "$ref": "#/definitions/v1.ListDiscordWebHooksQueueResults" } } } } }, + "/settings/{key}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Settings" + ], + "summary": "Returns a object based on the Key that was given.", + "parameters": [ + { + "type": "string", + "description": "Settings Key value", + "name": "key", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, "/sources": { "get": { "produces": [ @@ -350,13 +502,13 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSources" + "$ref": "#/definitions/v1.ListSources" } }, "400": { "description": "Unable to reach SQL or Data problems", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -384,19 +536,19 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSources" + "$ref": "#/definitions/v1.ListSources" } }, "400": { "description": "Unable to query SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "500": { "description": "Problems with data.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } } } @@ -431,25 +583,25 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.GetSource" + "$ref": "#/definitions/v1.GetSource" } }, "204": { "description": "No record found.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "400": { "description": "Unable to query SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "500": { "description": "Failed to process data from SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } } } @@ -545,25 +697,25 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.GetSource" + "$ref": "#/definitions/v1.GetSource" } }, "204": { "description": "No record found.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "400": { "description": "Unable to query SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "500": { "description": "Failed to process data from SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } } } @@ -634,19 +786,19 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSubscriptions" + "$ref": "#/definitions/v1.ListSubscriptions" } }, "400": { "description": "Unable to reach SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "500": { "description": "Failed to process data from SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } } } @@ -674,7 +826,7 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSubscriptions" + "$ref": "#/definitions/v1.ListSubscriptions" } } } @@ -702,19 +854,19 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSubscriptions" + "$ref": "#/definitions/v1.ListSubscriptions" } }, "400": { "description": "Unable to reach SQL or Data problems", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "500": { "description": "Data problems", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } } } @@ -733,7 +885,7 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSubscriptionDetails" + "$ref": "#/definitions/v1.ListSubscriptionDetails" } } } @@ -784,6 +936,146 @@ const docTemplate = `{ } }, "definitions": { + "domain.ArticleAndSourceModel": { + "type": "object", + "properties": { + "article": { + "$ref": "#/definitions/domain.ArticleDto" + }, + "source": { + "$ref": "#/definitions/domain.SourceDto" + } + } + }, + "domain.ArticleDetailedResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "payload": { + "$ref": "#/definitions/domain.ArticleAndSourceModel" + } + } + }, + "domain.ArticleDto": { + "type": "object", + "properties": { + "authorImage": { + "type": "string" + }, + "authorName": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "isVideo": { + "type": "boolean" + }, + "pubDate": { + "type": "string" + }, + "sourceId": { + "type": "integer" + }, + "tags": { + "type": "string" + }, + "thumbnail": { + "type": "string" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "domain.ArticleResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "payload": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ArticleDto" + } + } + } + }, + "domain.BaseResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "domain.DiscordWebHookDto": { + "type": "object", + "properties": { + "channel": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "server": { + "type": "string" + }, + "url": { + "description": "Name string ` + "`" + `json:\"name\"` + "`" + `\nKey string ` + "`" + `json:\"key\"` + "`" + `", + "type": "string" + } + } + }, + "domain.DiscordWebhookResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "payload": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.DiscordWebHookDto" + } + } + } + }, + "domain.SourceDto": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "source": { + "type": "string" + }, + "tags": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, "models.ArticleDetailsDto": { "type": "object", "properties": { @@ -831,53 +1123,6 @@ const docTemplate = `{ } } }, - "models.ArticleDto": { - "type": "object", - "properties": { - "authorImage": { - "type": "string" - }, - "authorName": { - "type": "string" - }, - "description": { - "type": "string" - }, - "id": { - "type": "string" - }, - "pubdate": { - "type": "string" - }, - "sourceid": { - "type": "string" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - }, - "url": { - "type": "string" - }, - "video": { - "type": "string" - }, - "videoHeight": { - "type": "integer" - }, - "videoWidth": { - "type": "integer" - } - } - }, "models.DiscordQueueDetailsDto": { "type": "object", "properties": { @@ -975,7 +1220,7 @@ const docTemplate = `{ } } }, - "routes.ApiError": { + "v1.ApiError": { "type": "object", "properties": { "message": { @@ -986,66 +1231,7 @@ const docTemplate = `{ } } }, - "routes.ArticleDetailsResult": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "$ref": "#/definitions/models.ArticleDetailsDto" - }, - "status": { - "type": "integer" - } - } - }, - "routes.ArticleGetResults": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "$ref": "#/definitions/models.ArticleDto" - }, - "status": { - "type": "integer" - } - } - }, - "routes.ArticlesListResults": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "type": "array", - "items": { - "$ref": "#/definitions/models.ArticleDto" - } - }, - "status": { - "type": "integer" - } - } - }, - "routes.GetDiscordWebhook": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "$ref": "#/definitions/models.DiscordWebHooksDto" - }, - "status": { - "type": "integer" - } - } - }, - "routes.GetSource": { + "v1.GetSource": { "type": "object", "properties": { "message": { @@ -1059,7 +1245,7 @@ const docTemplate = `{ } } }, - "routes.ListDiscordWebHooksQueueResults": { + "v1.ListDiscordWebHooksQueueResults": { "type": "object", "properties": { "message": { @@ -1076,24 +1262,7 @@ const docTemplate = `{ } } }, - "routes.ListDiscordWebhooks": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "type": "array", - "items": { - "$ref": "#/definitions/models.DiscordWebHooksDto" - } - }, - "status": { - "type": "integer" - } - } - }, - "routes.ListSources": { + "v1.ListSources": { "type": "object", "properties": { "message": { @@ -1110,7 +1279,7 @@ const docTemplate = `{ } } }, - "routes.ListSubscriptionDetails": { + "v1.ListSubscriptionDetails": { "type": "object", "properties": { "message": { @@ -1127,7 +1296,7 @@ const docTemplate = `{ } } }, - "routes.ListSubscriptions": { + "v1.ListSubscriptions": { "type": "object", "properties": { "message": { diff --git a/docs/swagger.json b/docs/swagger.json index b6d4557..141111c 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -28,7 +28,19 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.ArticlesListResults" + "$ref": "#/definitions/domain.ArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -46,7 +58,7 @@ "parameters": [ { "type": "string", - "description": "Source ID UUID", + "description": "source id", "name": "id", "in": "query", "required": true @@ -62,7 +74,19 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.ArticlesListResults" + "$ref": "#/definitions/domain.ArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -80,7 +104,7 @@ "parameters": [ { "type": "string", - "description": "uuid", + "description": "int", "name": "ID", "in": "path", "required": true @@ -90,7 +114,19 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.ArticleGetResults" + "$ref": "#/definitions/domain.ArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -108,7 +144,7 @@ "parameters": [ { "type": "string", - "description": "uuid", + "description": "int", "name": "ID", "in": "path", "required": true @@ -118,7 +154,19 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.ArticleDetailsResult" + "$ref": "#/definitions/domain.ArticleDetailedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -133,8 +181,27 @@ "Discord", "Webhook" ], - "summary": "Returns the top 100 entries from the queue to be processed.", - "responses": {} + "summary": "Returns the top 100", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/discord/webhooks/by/serverAndChannel": { @@ -167,7 +234,19 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.ListDiscordWebhooks" + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -203,7 +282,26 @@ "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/discord/webhooks/{ID}": { @@ -222,7 +320,26 @@ "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/discord/webhooks/{ID}/disable": { @@ -234,14 +351,33 @@ "summary": "Disables a Webhook from being used.", "parameters": [ { - "type": "string", + "type": "integer", "description": "id", "name": "id", "in": "path", "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/discord/webhooks/{ID}/enable": { @@ -253,7 +389,7 @@ "summary": "Enables a source to continue processing.", "parameters": [ { - "type": "string", + "type": "integer", "description": "id", "name": "id", "in": "path", @@ -275,7 +411,7 @@ "summary": "Returns the top 100 entries from the queue to be processed.", "parameters": [ { - "type": "string", + "type": "integer", "description": "id", "name": "id", "in": "path", @@ -286,27 +422,22 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/routes.GetDiscordWebhook" + "$ref": "#/definitions/domain.DiscordWebhookResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" } } } - }, - "patch": { - "tags": [ - "Discord", - "Webhook" - ], - "summary": "Updates a valid discord webhook ID based on the body given.", - "parameters": [ - { - "type": "string", - "description": "id", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": {} } }, "/queue/discord/webhooks": { @@ -322,12 +453,33 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListDiscordWebHooksQueueResults" + "$ref": "#/definitions/v1.ListDiscordWebHooksQueueResults" } } } } }, + "/settings/{key}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Settings" + ], + "summary": "Returns a object based on the Key that was given.", + "parameters": [ + { + "type": "string", + "description": "Settings Key value", + "name": "key", + "in": "path", + "required": true + } + ], + "responses": {} + } + }, "/sources": { "get": { "produces": [ @@ -341,13 +493,13 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSources" + "$ref": "#/definitions/v1.ListSources" } }, "400": { "description": "Unable to reach SQL or Data problems", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -375,19 +527,19 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSources" + "$ref": "#/definitions/v1.ListSources" } }, "400": { "description": "Unable to query SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "500": { "description": "Problems with data.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } } } @@ -422,25 +574,25 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.GetSource" + "$ref": "#/definitions/v1.GetSource" } }, "204": { "description": "No record found.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "400": { "description": "Unable to query SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "500": { "description": "Failed to process data from SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } } } @@ -536,25 +688,25 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.GetSource" + "$ref": "#/definitions/v1.GetSource" } }, "204": { "description": "No record found.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "400": { "description": "Unable to query SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "500": { "description": "Failed to process data from SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } } } @@ -625,19 +777,19 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSubscriptions" + "$ref": "#/definitions/v1.ListSubscriptions" } }, "400": { "description": "Unable to reach SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "500": { "description": "Failed to process data from SQL.", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } } } @@ -665,7 +817,7 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSubscriptions" + "$ref": "#/definitions/v1.ListSubscriptions" } } } @@ -693,19 +845,19 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSubscriptions" + "$ref": "#/definitions/v1.ListSubscriptions" } }, "400": { "description": "Unable to reach SQL or Data problems", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } }, "500": { "description": "Data problems", "schema": { - "$ref": "#/definitions/routes.ApiError" + "$ref": "#/definitions/v1.ApiError" } } } @@ -724,7 +876,7 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/routes.ListSubscriptionDetails" + "$ref": "#/definitions/v1.ListSubscriptionDetails" } } } @@ -775,6 +927,146 @@ } }, "definitions": { + "domain.ArticleAndSourceModel": { + "type": "object", + "properties": { + "article": { + "$ref": "#/definitions/domain.ArticleDto" + }, + "source": { + "$ref": "#/definitions/domain.SourceDto" + } + } + }, + "domain.ArticleDetailedResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "payload": { + "$ref": "#/definitions/domain.ArticleAndSourceModel" + } + } + }, + "domain.ArticleDto": { + "type": "object", + "properties": { + "authorImage": { + "type": "string" + }, + "authorName": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "isVideo": { + "type": "boolean" + }, + "pubDate": { + "type": "string" + }, + "sourceId": { + "type": "integer" + }, + "tags": { + "type": "string" + }, + "thumbnail": { + "type": "string" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "domain.ArticleResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "payload": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ArticleDto" + } + } + } + }, + "domain.BaseResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "domain.DiscordWebHookDto": { + "type": "object", + "properties": { + "channel": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "server": { + "type": "string" + }, + "url": { + "description": "Name string `json:\"name\"`\nKey string `json:\"key\"`", + "type": "string" + } + } + }, + "domain.DiscordWebhookResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "payload": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.DiscordWebHookDto" + } + } + } + }, + "domain.SourceDto": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "source": { + "type": "string" + }, + "tags": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, "models.ArticleDetailsDto": { "type": "object", "properties": { @@ -822,53 +1114,6 @@ } } }, - "models.ArticleDto": { - "type": "object", - "properties": { - "authorImage": { - "type": "string" - }, - "authorName": { - "type": "string" - }, - "description": { - "type": "string" - }, - "id": { - "type": "string" - }, - "pubdate": { - "type": "string" - }, - "sourceid": { - "type": "string" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "thumbnail": { - "type": "string" - }, - "title": { - "type": "string" - }, - "url": { - "type": "string" - }, - "video": { - "type": "string" - }, - "videoHeight": { - "type": "integer" - }, - "videoWidth": { - "type": "integer" - } - } - }, "models.DiscordQueueDetailsDto": { "type": "object", "properties": { @@ -966,7 +1211,7 @@ } } }, - "routes.ApiError": { + "v1.ApiError": { "type": "object", "properties": { "message": { @@ -977,66 +1222,7 @@ } } }, - "routes.ArticleDetailsResult": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "$ref": "#/definitions/models.ArticleDetailsDto" - }, - "status": { - "type": "integer" - } - } - }, - "routes.ArticleGetResults": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "$ref": "#/definitions/models.ArticleDto" - }, - "status": { - "type": "integer" - } - } - }, - "routes.ArticlesListResults": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "type": "array", - "items": { - "$ref": "#/definitions/models.ArticleDto" - } - }, - "status": { - "type": "integer" - } - } - }, - "routes.GetDiscordWebhook": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "$ref": "#/definitions/models.DiscordWebHooksDto" - }, - "status": { - "type": "integer" - } - } - }, - "routes.GetSource": { + "v1.GetSource": { "type": "object", "properties": { "message": { @@ -1050,7 +1236,7 @@ } } }, - "routes.ListDiscordWebHooksQueueResults": { + "v1.ListDiscordWebHooksQueueResults": { "type": "object", "properties": { "message": { @@ -1067,24 +1253,7 @@ } } }, - "routes.ListDiscordWebhooks": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "type": "array", - "items": { - "$ref": "#/definitions/models.DiscordWebHooksDto" - } - }, - "status": { - "type": "integer" - } - } - }, - "routes.ListSources": { + "v1.ListSources": { "type": "object", "properties": { "message": { @@ -1101,7 +1270,7 @@ } } }, - "routes.ListSubscriptionDetails": { + "v1.ListSubscriptionDetails": { "type": "object", "properties": { "message": { @@ -1118,7 +1287,7 @@ } } }, - "routes.ListSubscriptions": { + "v1.ListSubscriptions": { "type": "object", "properties": { "message": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index cb9d714..c0a9f74 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,5 +1,98 @@ basePath: /api definitions: + domain.ArticleAndSourceModel: + properties: + article: + $ref: '#/definitions/domain.ArticleDto' + source: + $ref: '#/definitions/domain.SourceDto' + type: object + domain.ArticleDetailedResponse: + properties: + message: + type: string + payload: + $ref: '#/definitions/domain.ArticleAndSourceModel' + type: object + domain.ArticleDto: + properties: + authorImage: + type: string + authorName: + type: string + description: + type: string + id: + type: integer + isVideo: + type: boolean + pubDate: + type: string + sourceId: + type: integer + tags: + type: string + thumbnail: + type: string + title: + type: string + url: + type: string + type: object + domain.ArticleResponse: + properties: + message: + type: string + payload: + items: + $ref: '#/definitions/domain.ArticleDto' + type: array + type: object + domain.BaseResponse: + properties: + message: + type: string + type: object + domain.DiscordWebHookDto: + properties: + channel: + type: string + enabled: + type: boolean + id: + type: integer + server: + type: string + url: + description: |- + Name string `json:"name"` + Key string `json:"key"` + type: string + type: object + domain.DiscordWebhookResponse: + properties: + message: + type: string + payload: + items: + $ref: '#/definitions/domain.DiscordWebHookDto' + type: array + type: object + domain.SourceDto: + properties: + enabled: + type: boolean + id: + type: integer + name: + type: string + source: + type: string + tags: + type: string + url: + type: string + type: object models.ArticleDetailsDto: properties: authorImage: @@ -31,37 +124,6 @@ definitions: videoWidth: type: integer type: object - models.ArticleDto: - properties: - authorImage: - type: string - authorName: - type: string - description: - type: string - id: - type: string - pubdate: - type: string - sourceid: - type: string - tags: - items: - type: string - type: array - thumbnail: - type: string - title: - type: string - url: - type: string - video: - type: string - videoHeight: - type: integer - videoWidth: - type: integer - type: object models.DiscordQueueDetailsDto: properties: article: @@ -125,52 +187,14 @@ definitions: sourceid: type: string type: object - routes.ApiError: + v1.ApiError: properties: message: type: string status: type: integer type: object - routes.ArticleDetailsResult: - properties: - message: - type: string - payload: - $ref: '#/definitions/models.ArticleDetailsDto' - status: - type: integer - type: object - routes.ArticleGetResults: - properties: - message: - type: string - payload: - $ref: '#/definitions/models.ArticleDto' - status: - type: integer - type: object - routes.ArticlesListResults: - properties: - message: - type: string - payload: - items: - $ref: '#/definitions/models.ArticleDto' - type: array - status: - type: integer - type: object - routes.GetDiscordWebhook: - properties: - message: - type: string - payload: - $ref: '#/definitions/models.DiscordWebHooksDto' - status: - type: integer - type: object - routes.GetSource: + v1.GetSource: properties: message: type: string @@ -179,7 +203,7 @@ definitions: status: type: integer type: object - routes.ListDiscordWebHooksQueueResults: + v1.ListDiscordWebHooksQueueResults: properties: message: type: string @@ -190,18 +214,7 @@ definitions: status: type: integer type: object - routes.ListDiscordWebhooks: - properties: - message: - type: string - payload: - items: - $ref: '#/definitions/models.DiscordWebHooksDto' - type: array - status: - type: integer - type: object - routes.ListSources: + v1.ListSources: properties: message: type: string @@ -212,7 +225,7 @@ definitions: status: type: integer type: object - routes.ListSubscriptionDetails: + v1.ListSubscriptionDetails: properties: message: type: string @@ -223,7 +236,7 @@ definitions: status: type: integer type: object - routes.ListSubscriptions: + v1.ListSubscriptions: properties: message: type: string @@ -252,14 +265,22 @@ paths: "200": description: OK schema: - $ref: '#/definitions/routes.ArticlesListResults' + $ref: '#/definitions/domain.ArticleResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Lists the top 25 records ordering from newest to oldest. tags: - Articles /articles/{ID}: get: parameters: - - description: uuid + - description: int in: path name: ID required: true @@ -270,14 +291,22 @@ paths: "200": description: OK schema: - $ref: '#/definitions/routes.ArticleGetResults' + $ref: '#/definitions/domain.ArticleResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Returns an article based on defined ID. tags: - Articles /articles/{ID}/details: get: parameters: - - description: uuid + - description: int in: path name: ID required: true @@ -288,14 +317,22 @@ paths: "200": description: OK schema: - $ref: '#/definitions/routes.ArticleDetailsResult' + $ref: '#/definitions/domain.ArticleDetailedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Returns an article and source based on defined ID. tags: - Articles /articles/by/sourceid: get: parameters: - - description: Source ID UUID + - description: source id in: query name: id required: true @@ -310,7 +347,15 @@ paths: "200": description: OK schema: - $ref: '#/definitions/routes.ArticlesListResults' + $ref: '#/definitions/domain.ArticleResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Finds the articles based on the SourceID provided. Returns the top 25. tags: @@ -319,8 +364,20 @@ paths: get: produces: - application/json - responses: {} - summary: Returns the top 100 entries from the queue to be processed. + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.DiscordWebhookResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' + summary: Returns the top 100 tags: - Discord - Webhook @@ -332,7 +389,19 @@ paths: name: id required: true type: string - responses: {} + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.DiscordWebhookResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Deletes a record by ID. tags: - Discord @@ -344,8 +413,20 @@ paths: in: path name: id required: true - type: string - responses: {} + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.DiscordWebhookResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Disables a Webhook from being used. tags: - Discord @@ -357,7 +438,7 @@ paths: in: path name: id required: true - type: string + type: integer responses: {} summary: Enables a source to continue processing. tags: @@ -370,30 +451,26 @@ paths: in: path name: id required: true - type: string + type: integer produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/routes.GetDiscordWebhook' + $ref: '#/definitions/domain.DiscordWebhookResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Returns the top 100 entries from the queue to be processed. tags: - Discord - Webhook - patch: - parameters: - - description: id - in: path - name: id - required: true - type: string - responses: {} - summary: Updates a valid discord webhook ID based on the body given. - tags: - - Discord - - Webhook /discord/webhooks/by/serverAndChannel: get: parameters: @@ -413,7 +490,15 @@ paths: "200": description: OK schema: - $ref: '#/definitions/routes.ListDiscordWebhooks' + $ref: '#/definitions/domain.DiscordWebhookResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Returns all the known web hooks based on the Server and Channel given. tags: - Discord @@ -436,7 +521,19 @@ paths: name: channel required: true type: string - responses: {} + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.DiscordWebhookResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Creates a new record for a discord web hook to post data to. tags: - Discord @@ -449,10 +546,24 @@ paths: "200": description: ok schema: - $ref: '#/definitions/routes.ListDiscordWebHooksQueueResults' + $ref: '#/definitions/v1.ListDiscordWebHooksQueueResults' summary: Returns the top 100 entries from the queue to be processed. tags: - Queue + /settings/{key}: + get: + parameters: + - description: Settings Key value + in: path + name: key + required: true + type: string + produces: + - application/json + responses: {} + summary: Returns a object based on the Key that was given. + tags: + - Settings /sources: get: produces: @@ -461,11 +572,11 @@ paths: "200": description: ok schema: - $ref: '#/definitions/routes.ListSources' + $ref: '#/definitions/v1.ListSources' "400": description: Unable to reach SQL or Data problems schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/domain.BaseResponse' summary: Lists the top 50 records tags: - Source @@ -483,19 +594,19 @@ paths: "200": description: ok schema: - $ref: '#/definitions/routes.GetSource' + $ref: '#/definitions/v1.GetSource' "204": description: No record found. schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' "400": description: Unable to query SQL. schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' "500": description: Failed to process data from SQL. schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' summary: Returns a single entity by ID tags: - Source @@ -548,15 +659,15 @@ paths: "200": description: ok schema: - $ref: '#/definitions/routes.ListSources' + $ref: '#/definitions/v1.ListSources' "400": description: Unable to query SQL. schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' "500": description: Problems with data. schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' summary: 'Lists the top 50 records based on the name given. Example: reddit' tags: - Source @@ -579,19 +690,19 @@ paths: "200": description: ok schema: - $ref: '#/definitions/routes.GetSource' + $ref: '#/definitions/v1.GetSource' "204": description: No record found. schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' "400": description: Unable to query SQL. schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' "500": description: Failed to process data from SQL. schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' summary: Returns a single entity by ID tags: - Source @@ -649,15 +760,15 @@ paths: "200": description: ok schema: - $ref: '#/definitions/routes.ListSubscriptions' + $ref: '#/definitions/v1.ListSubscriptions' "400": description: Unable to reach SQL. schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' "500": description: Failed to process data from SQL. schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' summary: Returns the top 100 entries from the queue to be processed. tags: - Subscription @@ -675,7 +786,7 @@ paths: "200": description: ok schema: - $ref: '#/definitions/routes.ListSubscriptions' + $ref: '#/definitions/v1.ListSubscriptions' summary: Returns the top 100 entries from the queue to be processed. tags: - Subscription @@ -693,15 +804,15 @@ paths: "200": description: ok schema: - $ref: '#/definitions/routes.ListSubscriptions' + $ref: '#/definitions/v1.ListSubscriptions' "400": description: Unable to reach SQL or Data problems schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' "500": description: Data problems schema: - $ref: '#/definitions/routes.ApiError' + $ref: '#/definitions/v1.ApiError' summary: Returns the top 100 entries from the queue to be processed. tags: - Subscription @@ -713,7 +824,7 @@ paths: "200": description: ok schema: - $ref: '#/definitions/routes.ListSubscriptionDetails' + $ref: '#/definitions/v1.ListSubscriptionDetails' summary: Returns the top 50 entries with full deatils on the source and output. tags: - Subscription diff --git a/internal/domain/dto.go b/internal/domain/dto.go index 0a59cd6..751724f 100644 --- a/internal/domain/dto.go +++ b/internal/domain/dto.go @@ -23,9 +23,9 @@ type DiscordQueueDto struct { } type DiscordWebHookDto struct { - ID uint `json:"id"` - Name string `json:"name"` - Key string `json:"key"` + ID int64 `json:"id"` + //Name string `json:"name"` + //Key string `json:"key"` Url string `json:"url"` Server string `json:"server"` Channel string `json:"channel"` diff --git a/internal/domain/entity.go b/internal/domain/entity.go index c892476..bc56a9b 100644 --- a/internal/domain/entity.go +++ b/internal/domain/entity.go @@ -35,8 +35,6 @@ type DiscordWebHookEntity struct { CreatedAt time.Time UpdatedAt time.Time DeletedAt time.Time - //Name string - //Key string Url string Server string Channel string diff --git a/internal/domain/responses.go b/internal/domain/responses.go index 5175940..7c8693a 100644 --- a/internal/domain/responses.go +++ b/internal/domain/responses.go @@ -15,7 +15,7 @@ type ArticleAndSourceModel struct { Source SourceDto `json:"source"` } -type ArticleDetailResponse struct { +type ArticleDetailedResponse struct { BaseResponse Payload ArticleAndSourceModel `json:"payload"` } diff --git a/internal/handler/v1/articles.go b/internal/handler/v1/articles.go index 8bae404..02ca2ef 100644 --- a/internal/handler/v1/articles.go +++ b/internal/handler/v1/articles.go @@ -45,7 +45,7 @@ func (s *Handler) listArticles(c echo.Context) error { // @Produce application/json // @Tags Articles // @Router /articles/{ID} [get] -// @Success 200 {object} ArticleGetResults "OK" +// @Success 200 {object} domain.ArticleResponse "OK" // @Failure 400 {object} domain.BaseResponse // @Failure 500 {object} domain.BaseResponse func (s *Handler) getArticle(c echo.Context) error { @@ -79,11 +79,11 @@ func (s *Handler) getArticle(c echo.Context) error { // @Produce application/json // @Tags Articles // @Router /articles/{ID}/details [get] -// @Success 200 {object} ArticleDetailsResult "OK" +// @Success 200 {object} domain.ArticleDetailedResponse "OK" // @Failure 400 {object} domain.BaseResponse // @Failure 500 {object} domain.BaseResponse func (s *Handler) getArticleDetails(c echo.Context) error { - p := domain.ArticleDetailResponse{ + p := domain.ArticleDetailedResponse{ BaseResponse: domain.BaseResponse{ Message: ResponseMessageSuccess, }, @@ -115,12 +115,12 @@ func (s *Handler) getArticleDetails(c echo.Context) error { // ListArticlesBySourceID // @Summary Finds the articles based on the SourceID provided. Returns the top 25. -// @Param id query string true +// @Param id query string true "source id" // @Param page query int false "Page to query" // @Produce application/json // @Tags Articles // @Router /articles/by/sourceid [get] -// @Success 200 {object} ArticlesListResults "OK" +// @Success 200 {object} domain.ArticleResponse "OK" // @Failure 400 {object} domain.BaseResponse // @Failure 500 {object} domain.BaseResponse func (s *Handler) ListArticlesBySourceId(c echo.Context) error { diff --git a/internal/handler/v1/discordwebhooks.go b/internal/handler/v1/discordwebhooks.go index 93ed20a..3e2cb11 100644 --- a/internal/handler/v1/discordwebhooks.go +++ b/internal/handler/v1/discordwebhooks.go @@ -1,84 +1,66 @@ package v1 import ( - "fmt" "net/http" + "strconv" "strings" - "git.jamestombleson.com/jtom38/newsbot-api/internal/database" "git.jamestombleson.com/jtom38/newsbot-api/internal/domain" - "git.jamestombleson.com/jtom38/newsbot-api/internal/domain/models" - "github.com/google/uuid" + "git.jamestombleson.com/jtom38/newsbot-api/internal/services" "github.com/labstack/echo/v4" ) -type ListDiscordWebhooks struct { - ApiStatusModel - Payload []models.DiscordWebHooksDto `json:"payload"` -} - -type GetDiscordWebhook struct { - ApiStatusModel - Payload models.DiscordWebHooksDto `json:"payload"` -} - // ListDiscordWebhooks -// @Summary Returns the top 100 entries from the queue to be processed. +// @Summary Returns the top 100 // @Produce application/json // @Tags Discord, Webhook // @Router /discord/webhooks [get] +// @Success 200 {object} domain.DiscordWebhookResponse +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) ListDiscordWebHooks(c echo.Context) error { - p := ListDiscordWebhooks{ - ApiStatusModel: ApiStatusModel{ - Message: "OK", - StatusCode: http.StatusOK, + p := domain.DiscordWebhookResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, }, } - res, err := s.dto.ListDiscordWebHooks(c.Request().Context(), 50) + res, err := s.repo.DiscordWebHooks.ListByServerName(c.Request().Context(), "") if err != nil { return c.JSON(http.StatusInternalServerError, err) } - p.Payload = res + p.Payload = services.DiscordWebhooksToDto(res) return c.JSON(http.StatusOK, p) } // GetDiscordWebHook // @Summary Returns the top 100 entries from the queue to be processed. // @Produce application/json -// @Param id path string true "id" +// @Param id path int true "id" // @Tags Discord, Webhook // @Router /discord/webhooks/{id} [get] -// @Success 200 {object} GetDiscordWebhook "OK" +// @Success 200 {object} domain.DiscordWebhookResponse "OK" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) GetDiscordWebHooksById(c echo.Context) error { - p := GetDiscordWebhook{ - ApiStatusModel: ApiStatusModel{ - Message: "OK", - StatusCode: http.StatusOK, + p := domain.DiscordWebhookResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, }, } - _id := c.Param("ID") - if _id == "" { - return c.JSON(http.StatusBadRequest, domain.BaseResponse{ - Message: ErrIdValueMissing, - }) + id, err := strconv.Atoi(c.Param("ID")) + if err != nil { + s.WriteError(c, err, http.StatusBadRequest) } - uuid, err := uuid.Parse(_id) + res, err := s.repo.DiscordWebHooks.GetById(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusBadRequest, domain.BaseResponse{ - Message: ErrUnableToParseId, - }) + s.WriteError(c, err, http.StatusInternalServerError) } - - res, err := s.dto.GetDiscordWebhook(c.Request().Context(), uuid) - if err != nil { - return c.JSON(http.StatusBadRequest, domain.BaseResponse{ - Message: ErrNoRecordFound, - }) - } - p.Payload = res + var dtos []domain.DiscordWebHookDto + dtos = append(dtos, services.DiscordWebhookToDto(res)) + p.Payload = dtos return c.JSON(http.StatusOK, p) } @@ -89,37 +71,32 @@ func (s *Handler) GetDiscordWebHooksById(c echo.Context) error { // @Param channel query string true "memes" // @Tags Discord, Webhook // @Router /discord/webhooks/by/serverAndChannel [get] -// @Success 200 {object} ListDiscordWebhooks "OK" +// @Success 200 {object} domain.DiscordWebhookResponse "OK" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) GetDiscordWebHooksByServerAndChannel(c echo.Context) error { - p := ListDiscordWebhooks{ - ApiStatusModel: ApiStatusModel{ - Message: "OK", - StatusCode: http.StatusOK, + p := domain.DiscordWebhookResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, }, } _server := c.QueryParam("server") if _server == "" { - return c.JSON(http.StatusBadRequest, domain.BaseResponse{ - Message: ErrIdValueMissing, - }) + s.WriteMessage(c, "server was not defined", http.StatusBadRequest) } _channel := c.QueryParam("channel") if _channel == "" { - return c.JSON(http.StatusBadRequest, domain.BaseResponse{ - Message: fmt.Sprintf("%s channel", ErrParameterMissing), - }) + s.WriteMessage(c, "channel was not defined", http.StatusBadRequest) } - res, err := s.dto.GetDiscordWebHookByServerAndChannel(c.Request().Context(), _server, _channel) + res, err := s.repo.DiscordWebHooks.ListByServerAndChannel(c.Request().Context(), _server, _channel) if err != nil { - return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusInternalServerError) } - p.Payload = res + p.Payload = services.DiscordWebhooksToDto(res) return c.JSON(http.StatusOK, p) } @@ -130,6 +107,9 @@ func (s *Handler) GetDiscordWebHooksByServerAndChannel(c echo.Context) error { // @Param channel query string true "Channel name" // @Tags Discord, Webhook // @Router /discord/webhooks/new [post] +// @Success 200 {object} domain.DiscordWebhookResponse "OK" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) NewDiscordWebHook(c echo.Context) error { _url := c.QueryParam("url") _server := c.QueryParam("server") @@ -155,26 +135,42 @@ func (s *Handler) NewDiscordWebHook(c echo.Context) error { Message: "channel is missing", }) } - params := database.CreateDiscordWebHookParams{ - ID: uuid.New(), - Url: _url, - Server: _server, - Channel: _channel, - Enabled: true, - } - s.Db.CreateDiscordWebHook(c.Request().Context(), params) - return c.JSON(http.StatusOK, params) + rows, err := s.repo.DiscordWebHooks.Create(c.Request().Context(), _url, _server, _channel, true) + if err != nil { + s.WriteError(c, err, http.StatusInternalServerError) + } + + if rows != 1 { + s.WriteMessage(c, "data was not written to database", http.StatusInternalServerError) + } + + item, err := s.repo.DiscordWebHooks.GetByUrl(c.Request().Context(), _url) + if err != nil { + s.WriteError(c, err, http.StatusInternalServerError) + } + + var dtos []domain.DiscordWebHookDto + dtos = append(dtos, services.DiscordWebhookToDto(item)) + + return c.JSON(http.StatusOK, domain.DiscordWebhookResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, + }, + Payload: dtos, + }) } // DisableDiscordWebHooks // @Summary Disables a Webhook from being used. -// @Param id path string true "id" +// @Param id path int true "id" // @Tags Discord, Webhook // @Router /discord/webhooks/{ID}/disable [post] +// @Success 200 {object} domain.DiscordWebhookResponse "OK" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) disableDiscordWebHook(c echo.Context) error { - id := c.Param("ID") - uuid, err := uuid.Parse(id) + id, err := strconv.Atoi(c.Param("ID")) if err != nil { return c.JSON(http.StatusBadRequest, domain.BaseResponse{ Message: err.Error(), @@ -182,45 +178,76 @@ func (s *Handler) disableDiscordWebHook(c echo.Context) error { } // Check to make sure we can find the record - _, err = s.Db.GetDiscordWebHooksByID(c.Request().Context(), uuid) + _, err = s.repo.DiscordWebHooks.GetById(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, err.Error()) + s.WriteError(c, err, http.StatusInternalServerError) } - err = s.Db.DisableDiscordWebHook(c.Request().Context(), uuid) + // flip the it + updated, err := s.repo.DiscordWebHooks.Disable(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusInternalServerError) } - return nil + + // make sure we got a row updated + if updated != 1 { + s.WriteMessage(c, "unexpected number of updates found", http.StatusInternalServerError) + } + + item, err := s.repo.DiscordWebHooks.GetById(c.Request().Context(), int64(id)) + if err != nil { + s.WriteError(c, err, http.StatusInternalServerError) + } + + var dtos []domain.DiscordWebHookDto + dtos = append(dtos, services.DiscordWebhookToDto(item)) + return c.JSON(http.StatusOK, domain.DiscordWebhookResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, + }, + Payload: dtos, + }) } // EnableDiscordWebHook // @Summary Enables a source to continue processing. -// @Param id path string true "id" +// @Param id path int true "id" // @Tags Discord, Webhook // @Router /discord/webhooks/{ID}/enable [post] func (s *Handler) enableDiscordWebHook(c echo.Context) error { - id := c.Param("ID") - uuid, err := uuid.Parse(id) + id, err := strconv.Atoi(c.Param("ID")) if err != nil { - return c.JSON(http.StatusBadRequest, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusBadRequest) } // Check to make sure we can find the record - _, err = s.Db.GetDiscordWebHooksByID(c.Request().Context(), uuid) + _, err = s.repo.DiscordWebHooks.GetById(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, err.Error()) + s.WriteError(c, err, http.StatusBadRequest) } - err = s.Db.EnableDiscordWebHook(c.Request().Context(), uuid) + updated, err := s.repo.DiscordWebHooks.Enable(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, err.Error()) + s.WriteError(c, err, http.StatusInternalServerError) } - return nil + + if updated != 1 { + s.WriteMessage(c, "unexpected number of updates found", http.StatusInternalServerError) + } + + item, err := s.repo.DiscordWebHooks.GetById(c.Request().Context(), int64(id)) + if err != nil { + s.WriteError(c, err, http.StatusInternalServerError) + } + + var dtos []domain.DiscordWebHookDto + dtos = append(dtos, services.DiscordWebhookToDto(item)) + return c.JSON(http.StatusOK, domain.DiscordWebhookResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, + }, + Payload: dtos, + }) } // DeleteDiscordWebHook @@ -228,28 +255,44 @@ func (s *Handler) enableDiscordWebHook(c echo.Context) error { // @Param id path string true "id" // @Tags Discord, Webhook // @Router /discord/webhooks/{ID} [delete] +// @Success 200 {object} domain.DiscordWebhookResponse "OK" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) deleteDiscordWebHook(c echo.Context) error { - //var item model.Sources = model.Sources{} - - id := c.Param("ID") - uuid, err := uuid.Parse(id) + id, err := strconv.Atoi(c.Param("ID")) if err != nil { return c.JSON(http.StatusBadRequest, err.Error()) } // Check to make sure we can find the record - _, err = s.Db.GetDiscordQueueByID(c.Request().Context(), uuid) + _, err = s.repo.DiscordWebHooks.GetById(c.Request().Context(), int64(id)) if err != nil { return c.JSON(http.StatusInternalServerError, err.Error()) } - // Delete the record - err = s.Db.DeleteDiscordWebHooks(c.Request().Context(), uuid) + // Soft delete the record + updated, err := s.repo.DiscordWebHooks.SoftDelete(c.Request().Context(), int64(id)) if err != nil { return c.JSON(http.StatusInternalServerError, err.Error()) } - return nil + if updated != 1 { + s.WriteMessage(c, "unexpected number of updates found", http.StatusInternalServerError) + } + + item, err := s.repo.DiscordWebHooks.GetById(c.Request().Context(), int64(id)) + if err != nil { + s.WriteError(c, err, http.StatusInternalServerError) + } + + var dtos []domain.DiscordWebHookDto + dtos = append(dtos, services.DiscordWebhookToDto(item)) + return c.JSON(http.StatusOK, domain.DiscordWebhookResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, + }, + Payload: dtos, + }) } // UpdateDiscordWebHook @@ -257,19 +300,31 @@ func (s *Handler) deleteDiscordWebHook(c echo.Context) error { // @Param id path string true "id" // @Tags Discord, Webhook // @Router /discord/webhooks/{id} [patch] -func (s *Handler) UpdateDiscordWebHook(c echo.Context) error { - id := c.Param("ID") - - uuid, err := uuid.Parse(id) - if err != nil { - return c.JSON(http.StatusInternalServerError, err.Error()) - } - - // Check to make sure we can find the record - _, err = s.Db.GetDiscordQueueByID(c.Request().Context(), uuid) - if err != nil { - return c.JSON(http.StatusInternalServerError, err.Error()) - } - - return nil -} +// @Success 200 {object} domain.DiscordWebhookResponse "OK" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse +//func (s *Handler) UpdateDiscordWebHook(c echo.Context) error { +// id, err := strconv.Atoi(c.Param("ID")) +// if err != nil { +// return c.JSON(http.StatusInternalServerError, err.Error()) +// } +// +// // Check to make sure we can find the record +// _, err = s.repo.DiscordWebHooks.GetById(c.Request().Context(), int64(id)) +// if err != nil { +// return c.JSON(http.StatusInternalServerError, err.Error()) +// } +// +// // Soft delete the record +// updated, err := s.repo.DiscordWebHooks(c.Request().Context(), int64(id)) +// if err != nil { +// return c.JSON(http.StatusInternalServerError, err.Error()) +// } +// +// _, err = s.Db.GetDiscordQueueByID(c.Request().Context(), uuid) +// if err != nil { +// return c.JSON(http.StatusInternalServerError, err.Error()) +// } +// +// return nil +//} diff --git a/internal/handler/v1/handler.go b/internal/handler/v1/handler.go index 655f72a..41bddcb 100644 --- a/internal/handler/v1/handler.go +++ b/internal/handler/v1/handler.go @@ -60,14 +60,14 @@ func NewServer(ctx context.Context, db *database.Queries, configs services.Confi articles.GET("/:id/details", s.getArticleDetails) articles.GET("/by/source/:id", s.ListArticlesBySourceId) - dwh := v1.Group("/discord/webhooks") - dwh.GET("/", s.ListDiscordWebHooks) - dwh.POST("/new", s.NewDiscordWebHook) - dwh.GET("/by/serverAndChannel", s.GetDiscordWebHooksByServerAndChannel) - dwh.GET("/:ID", s.GetDiscordWebHooksById) - dwh.DELETE("/:ID", s.deleteDiscordWebHook) - dwh.POST("/:ID/disable", s.disableDiscordWebHook) - dwh.POST("/:ID/enable", s.enableDiscordWebHook) + //dwh := v1.Group("/discord/webhooks") + //dwh.GET("/", s.ListDiscordWebHooks) + //dwh.POST("/new", s.NewDiscordWebHook) + //dwh.GET("/by/serverAndChannel", s.GetDiscordWebHooksByServerAndChannel) + //dwh.GET("/:ID", s.GetDiscordWebHooksById) + //dwh.DELETE("/:ID", s.deleteDiscordWebHook) + //dwh.POST("/:ID/disable", s.disableDiscordWebHook) + //dwh.POST("/:ID/enable", s.enableDiscordWebHook) //queue := v1.Group("/queue") //queue.GET("/discord/webhooks", s.ListDiscordWebhookQueue) // TODO this needs to be reworked diff --git a/internal/handler/v1/root_test.go b/internal/handler/v1/root_test.go deleted file mode 100644 index ba42722..0000000 --- a/internal/handler/v1/root_test.go +++ /dev/null @@ -1 +0,0 @@ -package v1_test diff --git a/internal/services/dtoconv.go b/internal/services/dtoconv.go index 1cddec3..6505dc5 100644 --- a/internal/services/dtoconv.go +++ b/internal/services/dtoconv.go @@ -26,6 +26,24 @@ func ArticleToDto(item domain.ArticleEntity) domain.ArticleDto { } } +func DiscordWebhooksToDto(items []domain.DiscordWebHookEntity) []domain.DiscordWebHookDto{ + var dtos []domain.DiscordWebHookDto + for _, item := range items { + dtos = append(dtos, DiscordWebhookToDto(item)) + } + return dtos +} + +func DiscordWebhookToDto(item domain.DiscordWebHookEntity) domain.DiscordWebHookDto { + return domain.DiscordWebHookDto{ + ID: item.ID, + Server: item.Server, + Channel: item.Channel, + Url: item.Url, + Enabled: item.Enabled, + } +} + func SourcesToDto(items []domain.SourceEntity) []domain.SourceDto { var dtos []domain.SourceDto for _, item := range items { -- 2.45.2 From 84d108f2dd40702c75a615bf47ddf59632be6986 Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 28 Apr 2024 19:29:49 -0700 Subject: [PATCH 2/2] source handlers have been updated --- docs/docs.go | 214 ++++++++++++++------- docs/swagger.json | 214 ++++++++++++++------- docs/swagger.yaml | 153 ++++++++++----- internal/domain/responses.go | 5 + internal/handler/v1/handler.go | 23 +-- internal/handler/v1/sources.go | 335 +++++++++++++++++---------------- internal/repository/source.go | 24 +++ 7 files changed, 620 insertions(+), 348 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 2ee6122..85bff2f 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -498,11 +498,19 @@ const docTemplate = `{ "Source" ], "summary": "Lists the top 50 records", + "parameters": [ + { + "type": "string", + "description": "page number", + "name": "page", + "in": "query" + } + ], "responses": { "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1.ListSources" + "$ref": "#/definitions/domain.SourcesResponse" } }, "400": { @@ -530,25 +538,31 @@ const docTemplate = `{ "name": "source", "in": "query", "required": true + }, + { + "type": "string", + "description": "page number", + "name": "page", + "in": "query" } ], "responses": { "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1.ListSources" + "$ref": "#/definitions/domain.SourcesResponse" } }, "400": { - "description": "Unable to query SQL.", + "description": "Bad Request", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } }, "500": { - "description": "Problems with data.", + "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -583,25 +597,19 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1.GetSource" - } - }, - "204": { - "description": "No record found.", - "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.SourcesResponse" } }, "400": { - "description": "Unable to query SQL.", + "description": "Bad Request", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } }, "500": { - "description": "Failed to process data from SQL.", + "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -629,7 +637,70 @@ const docTemplate = `{ "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/domain.SourcesResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } + } + }, + "/sources/new/rss": { + "post": { + "tags": [ + "Source" + ], + "summary": "Creates a new rss source to monitor.", + "parameters": [ + { + "type": "string", + "description": "Site Name", + "name": "name", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "RSS Url", + "name": "url", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/domain.SourcesResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/sources/new/twitch": { @@ -686,7 +757,7 @@ const docTemplate = `{ "summary": "Returns a single entity by ID", "parameters": [ { - "type": "string", + "type": "integer", "description": "uuid", "name": "id", "in": "path", @@ -697,25 +768,19 @@ const docTemplate = `{ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1.GetSource" - } - }, - "204": { - "description": "No record found.", - "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.SourcesResponse" } }, "400": { - "description": "Unable to query SQL.", + "description": "Bad Request", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } }, "500": { - "description": "Failed to process data from SQL.", + "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -745,14 +810,33 @@ const docTemplate = `{ "summary": "Disables a source from processing.", "parameters": [ { - "type": "string", + "type": "integer", "description": "id", "name": "id", "in": "path", "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/domain.SourcesResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/sources/{id}/enable": { @@ -770,7 +854,26 @@ const docTemplate = `{ "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/domain.SourcesResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/subscriptions": { @@ -1076,6 +1179,20 @@ const docTemplate = `{ } } }, + "domain.SourcesResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "payload": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.SourceDto" + } + } + } + }, "models.ArticleDetailsDto": { "type": "object", "properties": { @@ -1231,20 +1348,6 @@ const docTemplate = `{ } } }, - "v1.GetSource": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "$ref": "#/definitions/models.SourceDto" - }, - "status": { - "type": "integer" - } - } - }, "v1.ListDiscordWebHooksQueueResults": { "type": "object", "properties": { @@ -1262,23 +1365,6 @@ const docTemplate = `{ } } }, - "v1.ListSources": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "type": "array", - "items": { - "$ref": "#/definitions/models.SourceDto" - } - }, - "status": { - "type": "integer" - } - } - }, "v1.ListSubscriptionDetails": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 141111c..b4260d7 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -489,11 +489,19 @@ "Source" ], "summary": "Lists the top 50 records", + "parameters": [ + { + "type": "string", + "description": "page number", + "name": "page", + "in": "query" + } + ], "responses": { "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1.ListSources" + "$ref": "#/definitions/domain.SourcesResponse" } }, "400": { @@ -521,25 +529,31 @@ "name": "source", "in": "query", "required": true + }, + { + "type": "string", + "description": "page number", + "name": "page", + "in": "query" } ], "responses": { "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1.ListSources" + "$ref": "#/definitions/domain.SourcesResponse" } }, "400": { - "description": "Unable to query SQL.", + "description": "Bad Request", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } }, "500": { - "description": "Problems with data.", + "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -574,25 +588,19 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1.GetSource" - } - }, - "204": { - "description": "No record found.", - "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.SourcesResponse" } }, "400": { - "description": "Unable to query SQL.", + "description": "Bad Request", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } }, "500": { - "description": "Failed to process data from SQL.", + "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -620,7 +628,70 @@ "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/domain.SourcesResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } + } + }, + "/sources/new/rss": { + "post": { + "tags": [ + "Source" + ], + "summary": "Creates a new rss source to monitor.", + "parameters": [ + { + "type": "string", + "description": "Site Name", + "name": "name", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "RSS Url", + "name": "url", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/domain.SourcesResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/sources/new/twitch": { @@ -677,7 +748,7 @@ "summary": "Returns a single entity by ID", "parameters": [ { - "type": "string", + "type": "integer", "description": "uuid", "name": "id", "in": "path", @@ -688,25 +759,19 @@ "200": { "description": "ok", "schema": { - "$ref": "#/definitions/v1.GetSource" - } - }, - "204": { - "description": "No record found.", - "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.SourcesResponse" } }, "400": { - "description": "Unable to query SQL.", + "description": "Bad Request", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } }, "500": { - "description": "Failed to process data from SQL.", + "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/v1.ApiError" + "$ref": "#/definitions/domain.BaseResponse" } } } @@ -736,14 +801,33 @@ "summary": "Disables a source from processing.", "parameters": [ { - "type": "string", + "type": "integer", "description": "id", "name": "id", "in": "path", "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/domain.SourcesResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/sources/{id}/enable": { @@ -761,7 +845,26 @@ "required": true } ], - "responses": {} + "responses": { + "200": { + "description": "ok", + "schema": { + "$ref": "#/definitions/domain.SourcesResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/domain.BaseResponse" + } + } + } } }, "/subscriptions": { @@ -1067,6 +1170,20 @@ } } }, + "domain.SourcesResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "payload": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.SourceDto" + } + } + } + }, "models.ArticleDetailsDto": { "type": "object", "properties": { @@ -1222,20 +1339,6 @@ } } }, - "v1.GetSource": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "$ref": "#/definitions/models.SourceDto" - }, - "status": { - "type": "integer" - } - } - }, "v1.ListDiscordWebHooksQueueResults": { "type": "object", "properties": { @@ -1253,23 +1356,6 @@ } } }, - "v1.ListSources": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "payload": { - "type": "array", - "items": { - "$ref": "#/definitions/models.SourceDto" - } - }, - "status": { - "type": "integer" - } - } - }, "v1.ListSubscriptionDetails": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index c0a9f74..9638e3f 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -93,6 +93,15 @@ definitions: url: type: string type: object + domain.SourcesResponse: + properties: + message: + type: string + payload: + items: + $ref: '#/definitions/domain.SourceDto' + type: array + type: object models.ArticleDetailsDto: properties: authorImage: @@ -194,15 +203,6 @@ definitions: status: type: integer type: object - v1.GetSource: - properties: - message: - type: string - payload: - $ref: '#/definitions/models.SourceDto' - status: - type: integer - type: object v1.ListDiscordWebHooksQueueResults: properties: message: @@ -214,17 +214,6 @@ definitions: status: type: integer type: object - v1.ListSources: - properties: - message: - type: string - payload: - items: - $ref: '#/definitions/models.SourceDto' - type: array - status: - type: integer - type: object v1.ListSubscriptionDetails: properties: message: @@ -566,13 +555,18 @@ paths: - Settings /sources: get: + parameters: + - description: page number + in: query + name: page + type: string produces: - application/json responses: "200": description: ok schema: - $ref: '#/definitions/v1.ListSources' + $ref: '#/definitions/domain.SourcesResponse' "400": description: Unable to reach SQL or Data problems schema: @@ -587,26 +581,22 @@ paths: in: path name: id required: true - type: string + type: integer produces: - application/json responses: "200": description: ok schema: - $ref: '#/definitions/v1.GetSource' - "204": - description: No record found. - schema: - $ref: '#/definitions/v1.ApiError' + $ref: '#/definitions/domain.SourcesResponse' "400": - description: Unable to query SQL. + description: Bad Request schema: - $ref: '#/definitions/v1.ApiError' + $ref: '#/definitions/domain.BaseResponse' "500": - description: Failed to process data from SQL. + description: Internal Server Error schema: - $ref: '#/definitions/v1.ApiError' + $ref: '#/definitions/domain.BaseResponse' summary: Returns a single entity by ID tags: - Source @@ -628,8 +618,20 @@ paths: in: path name: id required: true - type: string - responses: {} + type: integer + responses: + "200": + description: ok + schema: + $ref: '#/definitions/domain.SourcesResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Disables a source from processing. tags: - Source @@ -641,7 +643,19 @@ paths: name: id required: true type: string - responses: {} + responses: + "200": + description: ok + schema: + $ref: '#/definitions/domain.SourcesResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Enables a source to continue processing. tags: - Source @@ -653,21 +667,25 @@ paths: name: source required: true type: string + - description: page number + in: query + name: page + type: string produces: - application/json responses: "200": description: ok schema: - $ref: '#/definitions/v1.ListSources' + $ref: '#/definitions/domain.SourcesResponse' "400": - description: Unable to query SQL. + description: Bad Request schema: - $ref: '#/definitions/v1.ApiError' + $ref: '#/definitions/domain.BaseResponse' "500": - description: Problems with data. + description: Internal Server Error schema: - $ref: '#/definitions/v1.ApiError' + $ref: '#/definitions/domain.BaseResponse' summary: 'Lists the top 50 records based on the name given. Example: reddit' tags: - Source @@ -690,19 +708,15 @@ paths: "200": description: ok schema: - $ref: '#/definitions/v1.GetSource' - "204": - description: No record found. - schema: - $ref: '#/definitions/v1.ApiError' + $ref: '#/definitions/domain.SourcesResponse' "400": - description: Unable to query SQL. + description: Bad Request schema: - $ref: '#/definitions/v1.ApiError' + $ref: '#/definitions/domain.BaseResponse' "500": - description: Failed to process data from SQL. + description: Internal Server Error schema: - $ref: '#/definitions/v1.ApiError' + $ref: '#/definitions/domain.BaseResponse' summary: Returns a single entity by ID tags: - Source @@ -719,10 +733,51 @@ paths: name: url required: true type: string - responses: {} + responses: + "200": + description: ok + schema: + $ref: '#/definitions/domain.SourcesResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' summary: Creates a new reddit source to monitor. tags: - Source + /sources/new/rss: + post: + parameters: + - description: Site Name + in: query + name: name + required: true + type: string + - description: RSS Url + in: query + name: url + required: true + type: string + responses: + "200": + description: ok + schema: + $ref: '#/definitions/domain.SourcesResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.BaseResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/domain.BaseResponse' + summary: Creates a new rss source to monitor. + tags: + - Source /sources/new/twitch: post: parameters: diff --git a/internal/domain/responses.go b/internal/domain/responses.go index 7c8693a..f6ca7ef 100644 --- a/internal/domain/responses.go +++ b/internal/domain/responses.go @@ -23,4 +23,9 @@ type ArticleDetailedResponse struct { type DiscordWebhookResponse struct { BaseResponse Payload []DiscordWebHookDto `json:"payload"` +} + +type SourcesResponse struct { + BaseResponse + Payload []SourceDto `json:"payload"` } \ No newline at end of file diff --git a/internal/handler/v1/handler.go b/internal/handler/v1/handler.go index 41bddcb..c510f65 100644 --- a/internal/handler/v1/handler.go +++ b/internal/handler/v1/handler.go @@ -23,14 +23,11 @@ type Handler struct { } const ( - HeaderContentType = "Content-Type" - - //ApplicationJson = "application/json" - - ErrParameterIdMissing = "The requested parameter ID was not found." - ErrParameterMissing = "The requested parameter was found found:" - ErrUnableToParseId = "Unable to parse the requested ID." - ErrRecordMissing = "The requested record was not found" + ErrParameterIdMissing = "The requested parameter ID was not found." + ErrParameterMissing = "The requested parameter was not found found:" + ErrUnableToParseId = "Unable to parse the requested ID" + ErrRecordMissing = "The requested record was not found" + ErrFailedToCreateRecord = "The record was not created due to a database problem" ResponseMessageSuccess = "Success" ) @@ -79,11 +76,11 @@ func NewServer(ctx context.Context, db *database.Queries, configs services.Confi sources.GET("/", s.listSources) sources.GET("/by/source", s.listSourcesBySource) sources.GET("/by/sourceAndName", s.GetSourceBySourceAndName) - sources.POST("/new/reddit", s.newRedditSource) - sources.POST("/new/youtube", s.newYoutubeSource) - sources.POST("/new/twitch", s.newTwitchSource) - - sources.GET("/:ID/", s.getSources) + //sources.POST("/new/reddit", s.newRedditSource) + //sources.POST("/new/youtube", s.newYoutubeSource) + //sources.POST("/new/twitch", s.newTwitchSource) + sources.POST("/new/rss", s.newRssSource) + sources.GET("/:ID/", s.getSource) sources.DELETE("/:ID/", s.deleteSources) sources.POST("/:ID/disable", s.disableSource) sources.POST("/:ID/enable", s.enableSource) diff --git a/internal/handler/v1/sources.go b/internal/handler/v1/sources.go index c725ddf..49e4d8f 100644 --- a/internal/handler/v1/sources.go +++ b/internal/handler/v1/sources.go @@ -5,11 +5,13 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" "strings" "git.jamestombleson.com/jtom38/newsbot-api/internal/database" "git.jamestombleson.com/jtom38/newsbot-api/internal/domain" "git.jamestombleson.com/jtom38/newsbot-api/internal/domain/models" + "git.jamestombleson.com/jtom38/newsbot-api/internal/services" "github.com/google/uuid" "github.com/labstack/echo/v4" ) @@ -26,115 +28,105 @@ type GetSource struct { // ListSources // @Summary Lists the top 50 records +// @Param page query string false "page number" // @Produce application/json // @Tags Source // @Router /sources [get] -// @Success 200 {object} ListSources "ok" -// @Failure 400 {object} domain.BaseResponse "Unable to reach SQL or Data problems" +// @Success 200 {object} domain.SourcesResponse "ok" +// @Failure 400 {object} domain.BaseResponse "Unable to reach SQL or Data problems" func (s *Handler) listSources(c echo.Context) error { - //TODO Add top? - /* - top := chi.URLParam(r, "top") - topInt, err := strconv.ParseInt(top, 0, 32) - if err != nil { - panic(err) - } - res, err := s.Db.ListSources(r.Context(), int32(topInt)) - */ - - p := ListSources{ - ApiStatusModel: ApiStatusModel{ - StatusCode: http.StatusOK, - Message: "OK", + resp := domain.SourcesResponse { + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, }, } + page, err := strconv.Atoi(c.QueryParam("page")) + if err != nil { + page = 0 + } + // Default way of showing all sources - items, err := s.dto.ListSources(c.Request().Context(), 50) + items, err := s.repo.Sources.List(c.Request().Context(), page, 25) if err != nil { s.WriteError(c, err, http.StatusInternalServerError) } - p.Payload = items - return c.JSON(http.StatusOK, p) + resp.Payload = services.SourcesToDto(items) + return c.JSON(http.StatusOK, resp) } // ListSourcesBySource // @Summary Lists the top 50 records based on the name given. Example: reddit -// @Param source query string true "Source Name" +// @Param source query string true "Source Name" +// @Param page query string false "page number" // @Produce application/json // @Tags Source // @Router /sources/by/source [get] -// @Success 200 {object} ListSources "ok" -// @Failure 400 {object} ApiError "Unable to query SQL." -// @Failure 500 {object} ApiError "Problems with data." +// @Success 200 {object} domain.SourcesResponse "ok" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) listSourcesBySource(c echo.Context) error { - //TODO Add top? - /* - top := chi.URLParam(r, "top") - topInt, err := strconv.ParseInt(top, 0, 32) - if err != nil { - panic(err) - } - res, err := s.Db.ListSources(r.Context(), int32(topInt)) - */ - - p := ListSources{ - ApiStatusModel: ApiStatusModel{ - StatusCode: http.StatusOK, - Message: "OK", + resp := domain.SourcesResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, }, } source := c.QueryParam("source") + if source == "" { + s.WriteMessage(c, fmt.Sprintf("%s source", ErrParameterMissing), http.StatusBadRequest) + } + + page, err := strconv.Atoi(c.QueryParam("page")) + if err != nil { + page = 0 + } // Shows the list by Sources.source - res, err := s.dto.ListSourcesBySource(c.Request().Context(), source) + items, err := s.repo.Sources.ListBySource(c.Request().Context(), page, 25, source) if err != nil { return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ Message: err.Error(), }) } - p.Payload = res - return c.JSON(http.StatusOK, p) + resp.Payload = services.SourcesToDto(items) + return c.JSON(http.StatusOK, resp) } // GetSource // @Summary Returns a single entity by ID -// @Param id path string true "uuid" +// @Param id path int true "uuid" // @Produce application/json // @Tags Source // @Router /sources/{id} [get] -// @Success 200 {object} GetSource "ok" -// @Failure 204 {object} ApiError "No record found." -// @Failure 400 {object} ApiError "Unable to query SQL." -// @Failure 500 {object} ApiError "Failed to process data from SQL." -func (s *Handler) getSources(c echo.Context) error { - payload := GetSource{ - ApiStatusModel: ApiStatusModel{ - Message: "OK", - StatusCode: http.StatusOK, +// @Success 200 {object} domain.SourcesResponse "ok" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse +func (s *Handler) getSource(c echo.Context) error { + resp := domain.SourcesResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, }, } - id := c.Param("ID") - uuid, err := uuid.Parse(id) + id, err := strconv.Atoi(c.Param("ID")) if err != nil { return c.JSON(http.StatusBadRequest, domain.BaseResponse{ Message: ErrUnableToParseId, }) } - res, err := s.dto.GetSourceById(c.Request().Context(), uuid) + item, err := s.repo.Sources.GetById(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ - Message: ErrNoRecordFound, - }) + s.WriteError(c, err, http.StatusInternalServerError) } - payload.Payload = res - return c.JSON(http.StatusOK, payload) + var dto []domain.SourceDto + dto = append(dto, services.SourceToDto(item)) + resp.Payload = dto + return c.JSON(http.StatusOK, resp) } // GetSourceByNameAndSource @@ -144,15 +136,13 @@ func (s *Handler) getSources(c echo.Context) error { // @Produce application/json // @Tags Source // @Router /sources/by/sourceAndName [get] -// @Success 200 {object} GetSource "ok" -// @Failure 204 {object} ApiError "No record found." -// @Failure 400 {object} ApiError "Unable to query SQL." -// @Failure 500 {object} ApiError "Failed to process data from SQL." +// @Success 200 {object} domain.SourcesResponse "ok" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) GetSourceBySourceAndName(c echo.Context) error { - p := GetSource{ - ApiStatusModel: ApiStatusModel{ - Message: "OK", - StatusCode: http.StatusOK, + resp := domain.SourcesResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, }, } @@ -164,25 +154,15 @@ func (s *Handler) GetSourceBySourceAndName(c echo.Context) error { }) } - //name := c.QueryParam("name") - //if name == "" { - // s.WriteError(w, "Parameter 'name' was missing in the query.", http.StatusInternalServerError) - // return c.JSON(http.bad) - //} - - //source := query["source"][0] - //if source == "" { - // s.WriteError(w, "The parameter 'source' was missing in the query.", http.StatusInternalServerError) - // return - //} - - item, err := s.dto.GetSourceByNameAndSource(c.Request().Context(), param.Name, param.Source) + item, err := s.repo.Sources.GetBySourceAndName(c.Request().Context(), param.Source, param.Name) if err != nil { return c.JSON(http.StatusInternalServerError, err.Error()) } - p.Payload = item - return c.JSON(http.StatusOK, p) + var dto []domain.SourceDto + dto = append(dto, services.SourceToDto(item)) + resp.Payload = dto + return c.JSON(http.StatusOK, resp) } // NewRedditSource @@ -191,7 +171,16 @@ func (s *Handler) GetSourceBySourceAndName(c echo.Context) error { // @Param url query string true "url" // @Tags Source // @Router /sources/new/reddit [post] +// @Success 200 {object} domain.SourcesResponse "ok" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) newRedditSource(c echo.Context) error { + resp := domain.SourcesResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, + }, + } + var param domain.NewSourceParamRequest err := c.Bind(¶m) if err != nil { @@ -199,10 +188,6 @@ func (s *Handler) newRedditSource(c echo.Context) error { Message: err.Error(), }) } - //query := r.URL.Query() - //_name := query["name"][0] - //_url := query["url"][0] - //_tags := query["tags"][0] if param.Url == "" { return c.JSON(http.StatusBadRequest, domain.BaseResponse{ @@ -215,40 +200,25 @@ func (s *Handler) newRedditSource(c echo.Context) error { }) } - /* - var tags string - if _tags == "" { - tags = fmt.Sprintf("twitch, %v", _name) - } else { - } - */ - - tags := fmt.Sprintf("twitch, %v", param.Name) - - params := database.CreateSourceParams{ - ID: uuid.New(), - Site: "reddit", - Name: param.Name, - Source: "reddit", - Type: "feed", - Enabled: true, - Url: param.Url, - Tags: tags, - } - err = s.Db.CreateSource(c.Request().Context(), params) + tags := fmt.Sprintf("twitch, %v, %s", param.Name, param.Tags) + rows, err := s.repo.Sources.Create(c.Request().Context(), domain.SourceCollectorReddit, param.Name, param.Url, tags, true) if err != nil { - return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusInternalServerError) } - //s.WriteJson(w, ¶ms) - bJson, err := json.Marshal(¶ms) + if rows != 1 { + s.WriteMessage(c, ErrFailedToCreateRecord, http.StatusInternalServerError) + } + + item, err := s.repo.Sources.GetBySourceAndName(c.Request().Context(), domain.SourceCollectorReddit, param.Name) if err != nil { - return c.JSON(http.StatusInternalServerError, err.Error()) + s.WriteError(c, err, http.StatusInternalServerError) } - return c.JSON(http.StatusOK, bJson) + var dto []domain.SourceDto + dto = append(dto, services.SourceToDto(item)) + resp.Payload = dto + return c.JSON(http.StatusOK, resp) } // NewYoutubeSource @@ -362,6 +332,57 @@ func (s *Handler) newTwitchSource(c echo.Context) error { return c.JSON(http.StatusOK, bJson) } +// NewRssSource +// @Summary Creates a new rss source to monitor. +// @Param name query string true "Site Name" +// @Param url query string true "RSS Url" +// @Tags Source +// @Router /sources/new/rss [post] +// @Success 200 {object} domain.SourcesResponse "ok" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse +func (s *Handler) newRssSource(c echo.Context) error { + resp := domain.SourcesResponse{ + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, + }, + } + + var param domain.NewSourceParamRequest + err := c.Bind(¶m) + if err != nil { + return c.JSON(http.StatusBadRequest, domain.BaseResponse{ + Message: err.Error(), + }) + } + + if param.Url == "" { + return c.JSON(http.StatusBadRequest, domain.BaseResponse{ + Message: "Url is missing a value", + }) + } + + tags := fmt.Sprintf("rss, %v, %s", param.Name, param.Tags) + rows, err := s.repo.Sources.Create(c.Request().Context(), domain.SourceCollectorRss, param.Name, param.Url, tags, true) + if err != nil { + s.WriteError(c, err, http.StatusInternalServerError) + } + + if rows != 1 { + s.WriteMessage(c, ErrFailedToCreateRecord, http.StatusInternalServerError) + } + + item, err := s.repo.Sources.GetBySourceAndName(c.Request().Context(), domain.SourceCollectorRss, param.Name) + if err != nil { + s.WriteError(c, err, http.StatusInternalServerError) + } + + var dto []domain.SourceDto + dto = append(dto, services.SourceToDto(item)) + resp.Payload = dto + return c.JSON(http.StatusOK, resp) +} + // DeleteSource // @Summary Marks a source as deleted based on its ID value. // @Param id path string true "id" @@ -409,46 +430,44 @@ func (s *Handler) deleteSources(c echo.Context) error { // DisableSource // @Summary Disables a source from processing. -// @Param id path string true "id" +// @Param id path int true "id" // @Tags Source // @Router /sources/{id}/disable [post] +// @Success 200 {object} domain.SourcesResponse "ok" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) disableSource(c echo.Context) error { - id := c.Param("ID") - uuid, err := uuid.Parse(id) + resp := domain.SourcesResponse { + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, + }, + } + + id, err := strconv.Atoi(c.Param("ID")) if err != nil { - return c.JSON(http.StatusBadRequest, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusBadRequest) } // Check to make sure we can find the record - _, err = s.Db.GetSourceByID(c.Request().Context(), uuid) + _, err = s.repo.Sources.GetById(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusBadRequest) } - err = s.Db.DisableSource(context.Background(), uuid) + _, err = s.repo.Sources.Disable(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusInternalServerError) } - p := ApiStatusModel{ - Message: "OK", - StatusCode: http.StatusOK, - } - - b, err := json.Marshal(p) + item, err := s.repo.Sources.GetById(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusInternalServerError) } - return c.JSON(http.StatusOK, b) + var dto []domain.SourceDto + dto = append(dto, services.SourceToDto(item)) + resp.Payload = dto + return c.JSON(http.StatusOK, resp) } // EnableSource @@ -456,39 +475,39 @@ func (s *Handler) disableSource(c echo.Context) error { // @Param id path string true "id" // @Tags Source // @Router /sources/{id}/enable [post] +// @Success 200 {object} domain.SourcesResponse "ok" +// @Failure 400 {object} domain.BaseResponse +// @Failure 500 {object} domain.BaseResponse func (s *Handler) enableSource(c echo.Context) error { - id := c.Param("ID") - uuid, err := uuid.Parse(id) + resp := domain.SourcesResponse { + BaseResponse: domain.BaseResponse{ + Message: ResponseMessageSuccess, + }, + } + + id, err := strconv.Atoi(c.Param("ID")) if err != nil { - return c.JSON(http.StatusBadRequest, err.Error()) + s.WriteError(c, err, http.StatusBadRequest) } // Check to make sure we can find the record - _, err = s.Db.GetSourceByID(c.Request().Context(), uuid) + _, err = s.repo.Sources.GetById(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusBadRequest) } - err = s.Db.EnableSource(c.Request().Context(), uuid) + _, err = s.repo.Sources.Enable(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusInternalServerError) } - p := ApiStatusModel{ - Message: "OK", - StatusCode: http.StatusOK, - } - - b, err := json.Marshal(p) + item, err := s.repo.Sources.GetById(c.Request().Context(), int64(id)) if err != nil { - return c.JSON(http.StatusInternalServerError, domain.BaseResponse{ - Message: err.Error(), - }) + s.WriteError(c, err, http.StatusInternalServerError) } - return c.JSON(http.StatusOK, b) + var dto []domain.SourceDto + dto = append(dto, services.SourceToDto(item)) + resp.Payload = dto + return c.JSON(http.StatusOK, resp) } diff --git a/internal/repository/source.go b/internal/repository/source.go index e17bd61..b534c4b 100644 --- a/internal/repository/source.go +++ b/internal/repository/source.go @@ -14,6 +14,7 @@ type Sources interface { GetById(ctx context.Context, id int64) (domain.SourceEntity, error) GetByDisplayName(ctx context.Context, displayName string) (domain.SourceEntity, error) GetBySource(ctx context.Context, source string) (domain.SourceEntity, error) + GetBySourceAndName(ctx context.Context, source, name string) (domain.SourceEntity, error) List(ctx context.Context, page, limit int) ([]domain.SourceEntity, error) ListBySource(ctx context.Context, page, limit int, source string) ([]domain.SourceEntity, error) Enable(ctx context.Context, id int64) (int64, error) @@ -115,6 +116,29 @@ func (r sourceRepository) GetBySource(ctx context.Context, source string) (domai return data[0], nil } +func (r sourceRepository) GetBySourceAndName(ctx context.Context, source, name string) (domain.SourceEntity, error) { + b := sqlbuilder.NewSelectBuilder() + b.Select("*") + b.From("Sources").Where( + b.Equal("Source", source), + b.Equal("Name", name), + ) + b.Limit(1) + query, args := b.Build() + + rows, err := r.conn.QueryContext(ctx, query, args...) + if err != nil { + return domain.SourceEntity{}, err + } + + data, err := r.processRows(rows) + if len(data) == 0 { + return domain.SourceEntity{}, err + } + + return data[0], nil +} + func (r sourceRepository) List(ctx context.Context, page, limit int) ([]domain.SourceEntity, error) { builder := sqlbuilder.NewSelectBuilder() builder.Select("*") -- 2.45.2