From aa993278b9cdff6a1c676c35a8965a2295089783 Mon Sep 17 00:00:00 2001 From: harold Date: Wed, 12 Mar 2025 11:26:25 +0500 Subject: [PATCH] add rotuer for get donats --- internal/api/http/handlers/donat/donat.go | 109 ++++++- internal/api/http/handlers/target/target.go | 14 +- internal/app/http/app.go | 5 +- internal/docs/docs.go | 304 ++++++++++++++++---- internal/docs/swagger.json | 304 ++++++++++++++++---- internal/docs/swagger.yaml | 202 ++++++++++--- internal/model/interfaces.go | 34 +-- internal/model/models.go | 37 ++- internal/model/sql/model.go | 4 +- internal/model/sql/query.go | 15 +- internal/repository/donat/donat.go | 41 ++- internal/repository/target/target.go | 14 +- internal/service/donat/donat.go | 44 ++- internal/service/target/target.go | 12 +- 14 files changed, 922 insertions(+), 217 deletions(-) diff --git a/internal/api/http/handlers/donat/donat.go b/internal/api/http/handlers/donat/donat.go index 78018b7..19f1172 100644 --- a/internal/api/http/handlers/donat/donat.go +++ b/internal/api/http/handlers/donat/donat.go @@ -6,7 +6,6 @@ import ( _ "donat-widget/internal/model/api" "donat-widget/pkg/custom_response" "donat-widget/pkg/validator" - "fmt" "github.com/labstack/echo/v4" "log/slog" "mime/multipart" @@ -56,16 +55,46 @@ func CreateDonat(donatService model.DonatService) echo.HandlerFunc { } } +// GetDonat godoc +// @Summary Get donats +// @Description Получает список донатов для указанного стримера с пагинацией +// @Tags Donate +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param page query int false "Номер страницы (по умолчанию 1)" default(1) +// @Param limit query int false "Количество элементов на странице (по умолчанию 10)" default(10) +// @Success 200 {array} model.Donat "Успешный возврат списка донатов" +// @Failure 400 {object} echo.HTTPError "Некорректный формат streamerID" +// @Failure 500 {object} echo.HTTPError "Внутренняя ошибка сервера" +// @Router /donat [get] func GetDonat(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { ctx := context.Background() - streamerID, err := strconv.Atoi(request.Param("streamerID")) - fmt.Println(streamerID) + page, err := strconv.Atoi(request.QueryParam("page")) + if page == 0 || err != nil { + page = 1 + } + limit, err := strconv.Atoi(request.QueryParam("limit")) + if limit == 0 || err != nil { + limit = 20 + } + + authData, err := donatService.CheckToken(request) + if err != nil { + slog.Error("Unauthorized") + return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) + } if err != nil { slog.Error(err.Error()) return request.JSON(http.StatusInternalServerError, err.Error()) } - donats, err := donatService.GetDonatByStreamerID(ctx, model.StreamerID(streamerID)) + donats, err := donatService.GetDonatsByStreamerID( + ctx, + authData.AccountID, + page, + limit, + ) if err != nil { slog.Error(err.Error()) return request.JSON(http.StatusInternalServerError, err.Error()) @@ -79,7 +108,7 @@ func GetDonat(donatService model.DonatService) echo.HandlerFunc { func MarkDonatPaid(donatService model.DonatService) echo.HandlerFunc { type MarkDonatPaidBody struct { - OrderID model.OrderID `json:"orderID"` + OrderID string `json:"orderID"` } return func(request echo.Context) error { ctx := context.Background() @@ -113,7 +142,7 @@ func MarkDonatView(donatService model.DonatService) echo.HandlerFunc { err = donatService.MarkDonatView( ctx, - model.DonatID(donatID), + donatID, ) if err != nil { return request.JSON(500, err.Error()) @@ -145,7 +174,7 @@ func GetInnerDonatePage(donatService model.DonatService) echo.HandlerFunc { ctx := context.Background() var innerPage model.InnerDonatePageResponse - innerPage, err = donatService.GetInnerDonatPage(ctx, model.StreamerID(authData.AccountID)) + innerPage, err = donatService.GetInnerDonatPage(ctx, authData.AccountID) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } @@ -447,11 +476,16 @@ func UpdateModerationSettings(donatService model.DonatService) echo.HandlerFunc return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) } - donatService.UpdateModerationSettings( + err = donatService.UpdateModerationSettings( ctx, authData.AccountID, body, ) + if err != nil { + slog.Error("Failed to update moderation settings", "error", err) + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to update moderation settings") + } + return request.JSON(http.StatusOK, "Success update") } } @@ -492,7 +526,7 @@ func GetDonationsStats(donatService model.DonatService) echo.HandlerFunc { } } -// DonateModeration godoc +// GetDonateModeration godoc // @Summary Get the latest donation in moderation // @Description Get the latest donation with status 'moderation' sorted by updated_at // @Tags Donate @@ -504,8 +538,8 @@ func GetDonationsStats(donatService model.DonatService) echo.HandlerFunc { // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 404 {object} echo.HTTPError "No donations in moderation found" // @Failure 500 {object} echo.HTTPError "Internal server error" -// @Router /donat/latest-moderation [get] -func DonateModeration(donatService model.DonatService) echo.HandlerFunc { +// @Router /donat-moderate/latest-moderation [get] +func GetDonateModeration(donatService model.DonatService) echo.HandlerFunc { return func(request echo.Context) error { authData, err := donatService.CheckToken(request) if err != nil { @@ -526,3 +560,56 @@ func DonateModeration(donatService model.DonatService) echo.HandlerFunc { return request.JSON(http.StatusOK, donation) } } + +// ModerateDonat godoc +// @Summary Update donat settings +// @Description Update donat settings such as accepted, show_text, play_content, show_name +// @Tags Donate +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param donat-id path int true "ID доната" +// @Param request body model.ModerationDonat true "Update fields" +// @Success 200 {string} string "Donat settings updated successfully" +// @Failure 400 {object} echo.HTTPError "Bad request" +// @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" +// @Failure 422 {object} echo.HTTPError "Validation error" +// @Router /donat-moderate/{donat-id} [patch] +func ModerateDonat(donatService model.DonatService) echo.HandlerFunc { + return func(request echo.Context) error { + ctx := context.Background() + donatID, err := strconv.Atoi(request.Param("donat-id")) + if err != nil { + slog.Error(err.Error()) + return echo.NewHTTPError(http.StatusUnprocessableEntity, "Incorrect donat id") + } + var body model.ModerationDonat + err = validator.ParseAndValidate(&body, request) + if err != nil { + slog.Error(err.Error()) + return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity") + } + + authData, err := donatService.CheckToken(request) + if err != nil { + slog.Error("Unauthorized") + return echo.NewHTTPError(http.StatusUnauthorized, err.Error()) + } + + // Проверка прав доступа (например, что пользователь является стримером) + // Это зависит от вашей бизнес-логики + + err = donatService.ModerateDonation( + ctx, + donatID, + authData.AccountID, + body, + ) + if err != nil { + slog.Error("Failed to update donat settings", "error", err) + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to update donat settings") + } + + return request.JSON(http.StatusOK, "Donat settings updated successfully") + } +} diff --git a/internal/api/http/handlers/target/target.go b/internal/api/http/handlers/target/target.go index fdcac5e..862a205 100644 --- a/internal/api/http/handlers/target/target.go +++ b/internal/api/http/handlers/target/target.go @@ -10,11 +10,11 @@ import ( func CreateTarget(targetService model.TargetService, authClient model.AuthClient) echo.HandlerFunc { type CreateTargetBody struct { - Amount model.DonatAmount `json:"amount"` - Text string `json:"text"` + Amount int `json:"amount"` + Text string `json:"text"` } type CreateTargetResponse struct { - TargetID model.TargetID `json:"targetID"` + TargetID int `json:"targetID"` } return func(request echo.Context) error { ctx := context.Background() @@ -34,8 +34,8 @@ func CreateTarget(targetService model.TargetService, authClient model.AuthClient return request.JSON(http.StatusInternalServerError, err.Error()) } - targetID, err := targetService.CreateTarget(ctx, model.StreamerID( - model.StreamerID(authData.AccountID)), + targetID, err := targetService.CreateTarget(ctx, + authData.AccountID, body.Amount, body.Text, ) @@ -49,7 +49,7 @@ func CreateTarget(targetService model.TargetService, authClient model.AuthClient func GetAllTarget(targetService model.TargetService) echo.HandlerFunc { type GetAllTargetBody struct { - StreamerID model.StreamerID `json:"streamerID"` + StreamerID int `json:"streamerID"` } return func(request echo.Context) error { ctx := context.Background() @@ -83,7 +83,7 @@ func AddAmountTarget( donatService model.DonatService, ) echo.HandlerFunc { type AddAmountTargetBody struct { - OrderID model.OrderID `json:"orderID"` + OrderID string `json:"orderID"` } return func(request echo.Context) error { ctx := context.Background() diff --git a/internal/app/http/app.go b/internal/app/http/app.go index e8bebc5..3cd952f 100644 --- a/internal/app/http/app.go +++ b/internal/app/http/app.go @@ -84,14 +84,15 @@ func IncludeDonatHandlers( server.GET(PREFIX+"/moderation-settings", GetModerationSettings(donatService)) server.PATCH(PREFIX+"/moderation-settings", UpdateModerationSettings(donatService)) - server.GET(PREFIX+"/donat/get/:streamerID", GetDonat(donatService)) + server.GET(PREFIX+"/donat", GetDonat(donatService)) server.POST(PREFIX+"/donat/view/:donatID", MarkDonatView(donatService)) server.POST(PREFIX+"/donat/paid", MarkDonatPaid(donatService)) server.GET(PREFIX+"/donat/period-stat", GetDonationsStats(donatService)) - server.GET(PREFIX+"/donat/latest-moderation", DonateModeration(donatService)) + server.GET(PREFIX+"/donat-moderate/latest-moderation", GetDonateModeration(donatService)) + server.PATCH(PREFIX+"/donat-moderate/:donat-id", ModerateDonat(donatService)) } func IncludeWidgetHandlers( diff --git a/internal/docs/docs.go b/internal/docs/docs.go index 3acc17a..7926a00 100644 --- a/internal/docs/docs.go +++ b/internal/docs/docs.go @@ -15,6 +15,181 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/donat": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Получает список донатов для указанного стримера с пагинацией", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Donate" + ], + "summary": "Get donats", + "parameters": [ + { + "type": "integer", + "default": 1, + "description": "Номер страницы (по умолчанию 1)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "default": 10, + "description": "Количество элементов на странице (по умолчанию 10)", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Успешный возврат списка донатов", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/donat-widget_internal_model.Donat" + } + } + }, + "400": { + "description": "Некорректный формат streamerID", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "500": { + "description": "Внутренняя ошибка сервера", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + }, + "/donat-moderate/latest-moderation": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Get the latest donation with status 'moderation' sorted by updated_at", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Donate" + ], + "summary": "Get the latest donation in moderation", + "responses": { + "200": { + "description": "Latest donation in moderation", + "schema": { + "$ref": "#/definitions/donat-widget_internal_model.DonationModeration" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "401": { + "description": "Unauthorized or expired token", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "404": { + "description": "No donations in moderation found", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + }, + "/donat-moderate/{donat-id}": { + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Update donat settings such as accepted, show_text, play_content, show_name", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Donate" + ], + "summary": "Update donat settings", + "parameters": [ + { + "type": "integer", + "description": "ID доната", + "name": "donat-id", + "in": "path", + "required": true + }, + { + "description": "Update fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/donat-widget_internal_model.ModerationDonat" + } + } + ], + "responses": { + "200": { + "description": "Donat settings updated successfully", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "401": { + "description": "Unauthorized or expired token", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "422": { + "description": "Validation error", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + }, "/donat-page": { "patch": { "security": [ @@ -93,58 +268,6 @@ const docTemplate = `{ } } }, - "/donat/latest-moderation": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Get the latest donation with status 'moderation' sorted by updated_at", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Donate" - ], - "summary": "Get the latest donation in moderation", - "responses": { - "200": { - "description": "Latest donation in moderation", - "schema": { - "$ref": "#/definitions/donat-widget_internal_model.DonationModeration" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/echo.HTTPError" - } - }, - "401": { - "description": "Unauthorized or expired token", - "schema": { - "$ref": "#/definitions/echo.HTTPError" - } - }, - "404": { - "description": "No donations in moderation found", - "schema": { - "$ref": "#/definitions/echo.HTTPError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/echo.HTTPError" - } - } - } - } - }, "/donat/period-stat": { "get": { "security": [ @@ -1099,6 +1222,66 @@ const docTemplate = `{ } } }, + "donat-widget_internal_model.Donat": { + "type": "object", + "properties": { + "accepted_time": { + "type": "string", + "format": "date-time", + "example": "2025-03-12T15:04:05Z" + }, + "amount": { + "type": "integer", + "example": 500 + }, + "donat_user": { + "type": "string", + "example": "Anonymous" + }, + "id": { + "type": "integer", + "example": 1 + }, + "order_id": { + "type": "string", + "format": "uuid", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "play_content": { + "type": "boolean", + "example": true + }, + "show_name": { + "type": "boolean", + "example": true + }, + "show_text": { + "type": "boolean", + "example": true + }, + "showed_time": { + "type": "string", + "format": "date-time", + "example": "2025-03-12T15:05:10Z" + }, + "status": { + "type": "string", + "example": "pending" + }, + "target_id": { + "type": "integer", + "example": 2002 + }, + "text": { + "type": "string", + "example": "Thank you for the stream!" + }, + "widget_id": { + "type": "integer", + "example": 5 + } + } + }, "donat-widget_internal_model.DonationModeration": { "type": "object", "properties": { @@ -1376,6 +1559,23 @@ const docTemplate = `{ } } }, + "donat-widget_internal_model.ModerationDonat": { + "type": "object", + "properties": { + "accepted": { + "type": "boolean" + }, + "play_content": { + "type": "boolean" + }, + "show_name": { + "type": "boolean" + }, + "show_text": { + "type": "boolean" + } + } + }, "donat-widget_internal_model.ModerationResponse": { "type": "object", "properties": { diff --git a/internal/docs/swagger.json b/internal/docs/swagger.json index 5484f99..b8401d8 100644 --- a/internal/docs/swagger.json +++ b/internal/docs/swagger.json @@ -8,6 +8,181 @@ }, "basePath": "/api/widget", "paths": { + "/donat": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Получает список донатов для указанного стримера с пагинацией", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Donate" + ], + "summary": "Get donats", + "parameters": [ + { + "type": "integer", + "default": 1, + "description": "Номер страницы (по умолчанию 1)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "default": 10, + "description": "Количество элементов на странице (по умолчанию 10)", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Успешный возврат списка донатов", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/donat-widget_internal_model.Donat" + } + } + }, + "400": { + "description": "Некорректный формат streamerID", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "500": { + "description": "Внутренняя ошибка сервера", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + }, + "/donat-moderate/latest-moderation": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Get the latest donation with status 'moderation' sorted by updated_at", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Donate" + ], + "summary": "Get the latest donation in moderation", + "responses": { + "200": { + "description": "Latest donation in moderation", + "schema": { + "$ref": "#/definitions/donat-widget_internal_model.DonationModeration" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "401": { + "description": "Unauthorized or expired token", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "404": { + "description": "No donations in moderation found", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + }, + "/donat-moderate/{donat-id}": { + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Update donat settings such as accepted, show_text, play_content, show_name", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Donate" + ], + "summary": "Update donat settings", + "parameters": [ + { + "type": "integer", + "description": "ID доната", + "name": "donat-id", + "in": "path", + "required": true + }, + { + "description": "Update fields", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/donat-widget_internal_model.ModerationDonat" + } + } + ], + "responses": { + "200": { + "description": "Donat settings updated successfully", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "401": { + "description": "Unauthorized or expired token", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "422": { + "description": "Validation error", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + }, "/donat-page": { "patch": { "security": [ @@ -86,58 +261,6 @@ } } }, - "/donat/latest-moderation": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Get the latest donation with status 'moderation' sorted by updated_at", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Donate" - ], - "summary": "Get the latest donation in moderation", - "responses": { - "200": { - "description": "Latest donation in moderation", - "schema": { - "$ref": "#/definitions/donat-widget_internal_model.DonationModeration" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/echo.HTTPError" - } - }, - "401": { - "description": "Unauthorized or expired token", - "schema": { - "$ref": "#/definitions/echo.HTTPError" - } - }, - "404": { - "description": "No donations in moderation found", - "schema": { - "$ref": "#/definitions/echo.HTTPError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/echo.HTTPError" - } - } - } - } - }, "/donat/period-stat": { "get": { "security": [ @@ -1092,6 +1215,66 @@ } } }, + "donat-widget_internal_model.Donat": { + "type": "object", + "properties": { + "accepted_time": { + "type": "string", + "format": "date-time", + "example": "2025-03-12T15:04:05Z" + }, + "amount": { + "type": "integer", + "example": 500 + }, + "donat_user": { + "type": "string", + "example": "Anonymous" + }, + "id": { + "type": "integer", + "example": 1 + }, + "order_id": { + "type": "string", + "format": "uuid", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "play_content": { + "type": "boolean", + "example": true + }, + "show_name": { + "type": "boolean", + "example": true + }, + "show_text": { + "type": "boolean", + "example": true + }, + "showed_time": { + "type": "string", + "format": "date-time", + "example": "2025-03-12T15:05:10Z" + }, + "status": { + "type": "string", + "example": "pending" + }, + "target_id": { + "type": "integer", + "example": 2002 + }, + "text": { + "type": "string", + "example": "Thank you for the stream!" + }, + "widget_id": { + "type": "integer", + "example": 5 + } + } + }, "donat-widget_internal_model.DonationModeration": { "type": "object", "properties": { @@ -1369,6 +1552,23 @@ } } }, + "donat-widget_internal_model.ModerationDonat": { + "type": "object", + "properties": { + "accepted": { + "type": "boolean" + }, + "play_content": { + "type": "boolean" + }, + "show_name": { + "type": "boolean" + }, + "show_text": { + "type": "boolean" + } + } + }, "donat-widget_internal_model.ModerationResponse": { "type": "object", "properties": { diff --git a/internal/docs/swagger.yaml b/internal/docs/swagger.yaml index d4dcca6..485469d 100644 --- a/internal/docs/swagger.yaml +++ b/internal/docs/swagger.yaml @@ -69,6 +69,51 @@ definitions: streamer_id: type: integer type: object + donat-widget_internal_model.Donat: + properties: + accepted_time: + example: "2025-03-12T15:04:05Z" + format: date-time + type: string + amount: + example: 500 + type: integer + donat_user: + example: Anonymous + type: string + id: + example: 1 + type: integer + order_id: + example: 550e8400-e29b-41d4-a716-446655440000 + format: uuid + type: string + play_content: + example: true + type: boolean + show_name: + example: true + type: boolean + show_text: + example: true + type: boolean + showed_time: + example: "2025-03-12T15:05:10Z" + format: date-time + type: string + status: + example: pending + type: string + target_id: + example: 2002 + type: integer + text: + example: Thank you for the stream! + type: string + widget_id: + example: 5 + type: integer + type: object donat-widget_internal_model.DonationModeration: properties: accepted: @@ -272,6 +317,17 @@ definitions: ru_name: type: string type: object + donat-widget_internal_model.ModerationDonat: + properties: + accepted: + type: boolean + play_content: + type: boolean + show_name: + type: boolean + show_text: + type: boolean + type: object donat-widget_internal_model.ModerationResponse: properties: duration: @@ -415,6 +471,119 @@ info: title: Donate Auth Documentation version: "3.0" paths: + /donat: + get: + consumes: + - application/json + description: Получает список донатов для указанного стримера с пагинацией + parameters: + - default: 1 + description: Номер страницы (по умолчанию 1) + in: query + name: page + type: integer + - default: 10 + description: Количество элементов на странице (по умолчанию 10) + in: query + name: limit + type: integer + produces: + - application/json + responses: + "200": + description: Успешный возврат списка донатов + schema: + items: + $ref: '#/definitions/donat-widget_internal_model.Donat' + type: array + "400": + description: Некорректный формат streamerID + schema: + $ref: '#/definitions/echo.HTTPError' + "500": + description: Внутренняя ошибка сервера + schema: + $ref: '#/definitions/echo.HTTPError' + security: + - BearerAuth: [] + summary: Get donats + tags: + - Donate + /donat-moderate/{donat-id}: + patch: + consumes: + - application/json + description: Update donat settings such as accepted, show_text, play_content, + show_name + parameters: + - description: ID доната + in: path + name: donat-id + required: true + type: integer + - description: Update fields + in: body + name: request + required: true + schema: + $ref: '#/definitions/donat-widget_internal_model.ModerationDonat' + produces: + - application/json + responses: + "200": + description: Donat settings updated successfully + schema: + type: string + "400": + description: Bad request + schema: + $ref: '#/definitions/echo.HTTPError' + "401": + description: Unauthorized or expired token + schema: + $ref: '#/definitions/echo.HTTPError' + "422": + description: Validation error + schema: + $ref: '#/definitions/echo.HTTPError' + security: + - BearerAuth: [] + summary: Update donat settings + tags: + - Donate + /donat-moderate/latest-moderation: + get: + consumes: + - application/json + description: Get the latest donation with status 'moderation' sorted by updated_at + produces: + - application/json + responses: + "200": + description: Latest donation in moderation + schema: + $ref: '#/definitions/donat-widget_internal_model.DonationModeration' + "400": + description: Bad request + schema: + $ref: '#/definitions/echo.HTTPError' + "401": + description: Unauthorized or expired token + schema: + $ref: '#/definitions/echo.HTTPError' + "404": + description: No donations in moderation found + schema: + $ref: '#/definitions/echo.HTTPError' + "500": + description: Internal server error + schema: + $ref: '#/definitions/echo.HTTPError' + security: + - BearerAuth: [] + summary: Get the latest donation in moderation + tags: + - Donate /donat-page: patch: description: Update personal streamer donate page with optional background and @@ -505,39 +674,6 @@ paths: summary: Create donat tags: - Donate - /donat/latest-moderation: - get: - consumes: - - application/json - description: Get the latest donation with status 'moderation' sorted by updated_at - produces: - - application/json - responses: - "200": - description: Latest donation in moderation - schema: - $ref: '#/definitions/donat-widget_internal_model.DonationModeration' - "400": - description: Bad request - schema: - $ref: '#/definitions/echo.HTTPError' - "401": - description: Unauthorized or expired token - schema: - $ref: '#/definitions/echo.HTTPError' - "404": - description: No donations in moderation found - schema: - $ref: '#/definitions/echo.HTTPError' - "500": - description: Internal server error - schema: - $ref: '#/definitions/echo.HTTPError' - security: - - BearerAuth: [] - summary: Get the latest donation in moderation - tags: - - Donate /donat/period-stat: get: consumes: diff --git a/internal/model/interfaces.go b/internal/model/interfaces.go index 3d51b31..7f3f53d 100644 --- a/internal/model/interfaces.go +++ b/internal/model/interfaces.go @@ -77,13 +77,13 @@ type DonatService interface { CreateDonat(ctx context.Context, streamerLogin, text, donatUser string, targetID, amount int) (api.CreatePaymentResponse, error) - GetDonatByStreamerID(ctx context.Context, streamerID StreamerID) ([]*Donat, error) - GetDonatByOrderID(ctx context.Context, orderID OrderID) (*Donat, error) + GetDonatsByStreamerID(ctx context.Context, streamerID, page, limit int) ([]*Donat, error) + GetDonatByOrderID(ctx context.Context, orderID string) (*Donat, error) - MarkDonatPaid(ctx context.Context, orderID OrderID) error - MarkDonatView(ctx context.Context, DonatID DonatID) error + MarkDonatPaid(ctx context.Context, orderID string) error + MarkDonatView(ctx context.Context, donatID int) error - GetInnerDonatPage(ctx context.Context, streamerID StreamerID) (InnerDonatePageResponse, error) + GetInnerDonatPage(ctx context.Context, streamerID int) (InnerDonatePageResponse, error) GetOuterDonatPage(ctx context.Context, streamerLogin string) (OuterDonatePageResponse, error) UpdateDonatePage( ctx context.Context, @@ -104,6 +104,7 @@ type DonatService interface { GetDonationsStats(ctx context.Context, streamerID int, period string) (DonationSummaryResponse, error) GetDonatModeration(ctx context.Context, streamerID int) (DonationModeration, error) + ModerateDonation(ctx context.Context, donatID, streamerID int, updateModel ModerationDonat) error } type DonatRepo interface { @@ -118,13 +119,13 @@ type DonatRepo interface { donatUser string, ) error - GetDonatByStreamerID(ctx context.Context, streamerID StreamerID) ([]*Donat, error) - GetDonatByOrderID(ctx context.Context, orderID OrderID) (*Donat, error) + GetDonatsByStreamerID(ctx context.Context, streamerID, page, limit int) ([]*Donat, error) + GetDonatByOrderID(ctx context.Context, orderID string) (*Donat, error) - MarkDonatPaid(ctx context.Context, orderID OrderID) error - MarkDonatView(ctx context.Context, DonatID DonatID) error + MarkDonatPaid(ctx context.Context, orderID string) error + MarkDonatView(ctx context.Context, DonatID int) error - GetDonatPage(ctx context.Context, streamerID StreamerID) (DonatePage, error) + GetDonatPage(ctx context.Context, streamerID int) (DonatePage, error) GetDonatPageByLogin(ctx context.Context, streamerLogin string) (DonatePage, error) UpdateDonatePage( @@ -158,20 +159,21 @@ type DonatRepo interface { GetDonationsSummary(ctx context.Context, streamerID int, period string) (DonationSummary, error) GetDonatModeration(ctx context.Context, streamerID int) (DonationModeration, error) + ModerateDonation(ctx context.Context, donatID, streamerID int, updateModel ModerationDonat) error } type TargetService interface { CheckToken(request echo.Context) (api.CheckTokenResponse, error) - CreateTarget(ctx context.Context, streamerID StreamerID, amount DonatAmount, text string) (TargetID, error) - GetAllTarget(ctx context.Context, streamerID StreamerID) ([]*Target, error) - AddAmountToTarget(ctx context.Context, targetID TargetID, amount DonatAmount) error + CreateTarget(ctx context.Context, streamerID int, amount int, text string) (int, error) + GetAllTarget(ctx context.Context, streamerID int) ([]*Target, error) + AddAmountToTarget(ctx context.Context, targetID, amount int) error } type TargetRepo interface { - CreateTarget(ctx context.Context, streamerID StreamerID, amount DonatAmount, text string) (TargetID, error) - GetAllTarget(ctx context.Context, streamerID StreamerID) ([]*Target, error) - AddAmountToTarget(ctx context.Context, targetID TargetID, amount DonatAmount) error + CreateTarget(ctx context.Context, streamerID int, amount int, text string) (int, error) + GetAllTarget(ctx context.Context, streamerID int) ([]*Target, error) + AddAmountToTarget(ctx context.Context, targetID int, amount int) error } type Error interface { diff --git a/internal/model/models.go b/internal/model/models.go index 2b5a616..9cda152 100644 --- a/internal/model/models.go +++ b/internal/model/models.go @@ -59,20 +59,22 @@ type UpdateWidget struct { } type Donat struct { - ID DonatID `db:"id"` - StreamerID StreamerID `db:"streamer_id"` - WidgetID WidgetID `db:"widget_id"` - OrderID OrderID `db:"order_id"` - TargetID TargetID `db:"target_id"` - - Text string `db:"text"` - DonatUser string `db:"donat_user"` - Amount DonatAmount `db:"amount"` - - status string `db:"status"` - - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` + ID int `db:"id" json:"id" example:"1" description:"Unique identifier of the donation"` + WidgetID int `db:"widget_id" json:"widget_id" example:"5" description:"ID of the widget"` + StreamerID int `db:"streamer_id" json:"-" example:"1" description:"ID of the streamer"` + OrderID string `db:"order_id" json:"order_id" format:"uuid" example:"550e8400-e29b-41d4-a716-446655440000" description:"Unique order identifier"` + TargetID int `db:"target_id" json:"target_id,omitempty" example:"2002" description:"Optional target ID"` + Status string `db:"status" json:"status" example:"pending" description:"Donation status (e.g., pending, accepted, rejected)"` + Text string `db:"text" json:"text" example:"Thank you for the stream!" description:"Donation message text"` + Amount int `db:"amount" json:"amount" example:"500" description:"Donation amount in cents"` + DonatUser string `db:"donat_user" json:"donat_user" example:"Anonymous" description:"Name of the donator (or 'Anonymous')"` + AcceptedTime *time.Time `db:"accepted_time" json:"accepted_time,omitempty" format:"date-time" example:"2025-03-12T15:04:05Z" description:"Timestamp when the donation was accepted"` + ShowName bool `db:"show_name" json:"show_name" example:"true" description:"Whether to show the donator's name"` + ShowText bool `db:"show_text" json:"show_text" example:"true" description:"Whether to show the donation message"` + PlayContent bool `db:"play_content" json:"play_content" example:"true" description:"Whether to play media content (e.g., TTS, sound)"` + ShowedTime *time.Time `db:"showed_time" json:"showed_time" format:"date-time" example:"2025-03-12T15:05:10Z" description:"Timestamp when the donation was displayed on stream"` + CreatedAt time.Time `db:"created_at" json:"-" format:"date-time" example:"2025-03-12T15:04:05Z" description:"Timestamp when the donation was created"` + UpdatedAt time.Time `db:"updated_at" json:"-" format:"date-time" example:"2025-03-12T15:04:05Z" description:"Timestamp when the donation was last updated"` } type Target struct { @@ -293,6 +295,13 @@ type DonationModeration struct { UpdatedAt time.Time `db:"updated_at" json:"updated_at" example:"2025-03-09T12:49:21.75005Z"` // Дата последнего обновления } +type ModerationDonat struct { + Accepted *bool `json:"accepted"` + ShowText *bool `json:"show_text"` + PlayContent *bool `json:"play_content"` + ShowName *bool `json:"show_name"` +} + //func (widget *GetWidgetDb) GetMediaUrl(mediaType MediaType) MediaUrl { // var mediaUrl MediaUrl // if mediaType == "background_url" { diff --git a/internal/model/sql/model.go b/internal/model/sql/model.go index 17a8294..e0e490a 100644 --- a/internal/model/sql/model.go +++ b/internal/model/sql/model.go @@ -44,12 +44,12 @@ CREATE TABLE IF NOT EXISTS donats ( amount INTEGER NOT NULL, donat_user TEXT NOT NULL, - accepted BOOLEAN NOT NULL DEFAULT 'false', + accepted_time TIMESTAMP, show_name BOOLEAN NOT NULL DEFAULT 'true', show_text BOOLEAN NOT NULL DEFAULT 'true', play_content BOOLEAN NOT NULL DEFAULT 'true', - showed BOOLEAN NOT NULL DEFAULT 'false', + showed_time TIMESTAMP, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP diff --git a/internal/model/sql/query.go b/internal/model/sql/query.go index 9561ecb..a74eb13 100644 --- a/internal/model/sql/query.go +++ b/internal/model/sql/query.go @@ -60,8 +60,12 @@ WHERE order_id = (@order_id); ` var GetDonatByStreamerID = ` SELECT * FROM donats -WHERE streamer_id = (@streamer_id) AND paid = (@paid) AND view = (@view); +WHERE streamer_id = @streamer_id + AND accepted_time IS NOT NULL +ORDER BY created_at DESC +LIMIT @limit OFFSET @offset; ` + var GetDonatByOrderID = ` SELECT * FROM donats WHERE order_id = (@order_id); @@ -445,3 +449,12 @@ ORDER BY updated_at DESC LIMIT 1; ` + +var ModerateDonat = ` + UPDATE donats + SET + accepted = @accepted, + show_text = @show_text, + play_content = @play_content, + show_name = @show_name + WHERE id = @donat_id AND streamer_id = @streamer_id AND status = 'moderation'` diff --git a/internal/repository/donat/donat.go b/internal/repository/donat/donat.go index 1025f2c..b31ac27 100644 --- a/internal/repository/donat/donat.go +++ b/internal/repository/donat/donat.go @@ -52,14 +52,18 @@ func (repoDonat *RepoDonat) CreateDonat( return nil } -func (repoDonat *RepoDonat) GetDonatByStreamerID( +func (repoDonat *RepoDonat) GetDonatsByStreamerID( ctx context.Context, - streamerID model.StreamerID, + streamerID int, + page int, + limit int, ) ([]*model.Donat, error) { + offset := (page - 1) * limit args := pgx.NamedArgs{ "streamer_id": streamerID, "paid": true, - "view": false, + "offset": offset, + "page": page, } rows, err := repoDonat.db.Select(ctx, sql.GetDonatByStreamerID, args) if err != nil { @@ -79,7 +83,7 @@ func (repoDonat *RepoDonat) GetDonatByStreamerID( func (repoDonat *RepoDonat) GetDonatByOrderID( ctx context.Context, - orderID model.OrderID, + orderID string, ) (*model.Donat, error) { args := pgx.NamedArgs{ "order_id": orderID, @@ -105,7 +109,7 @@ func (repoDonat *RepoDonat) GetDonatByOrderID( func (repoDonat *RepoDonat) MarkDonatView( ctx context.Context, - donatID model.DonatID, + donatID int, ) error { args := pgx.NamedArgs{ "id": donatID, @@ -122,7 +126,7 @@ func (repoDonat *RepoDonat) MarkDonatView( func (repoDonat *RepoDonat) MarkDonatPaid( ctx context.Context, - orderID model.OrderID, + orderID string, ) error { args := pgx.NamedArgs{ "order_id": orderID, @@ -139,7 +143,7 @@ func (repoDonat *RepoDonat) MarkDonatPaid( func (repoDonat *RepoDonat) GetDonatPage( ctx context.Context, - streamerID model.StreamerID, + streamerID int, ) (model.DonatePage, error) { args := pgx.NamedArgs{ "streamer_id": streamerID, @@ -719,3 +723,26 @@ func (repoDonat *RepoDonat) GetDonatModeration( return donation, nil } + +func (repoDonat *RepoDonat) ModerateDonation( + ctx context.Context, + donatID int, + streamerID int, + updateModel model.ModerationDonat, +) error { + args := pgx.NamedArgs{ + "donat_id": donatID, + "streamer_id": streamerID, + "accepted": updateModel.Accepted, + "show_name": updateModel.ShowName, + "show_text": updateModel.ShowText, + "play_content": updateModel.PlayContent, + } + + err := repoDonat.db.Exec(ctx, sql.ModerateDonat, args) + if err != nil { + slog.Error("Failed to update donat", "error", err) + return err + } + return nil +} diff --git a/internal/repository/target/target.go b/internal/repository/target/target.go index 4210a13..f476611 100644 --- a/internal/repository/target/target.go +++ b/internal/repository/target/target.go @@ -21,10 +21,10 @@ type RepoTarget struct { func (targetRepo *RepoTarget) CreateTarget( ctx context.Context, - streamerID model.StreamerID, - amount model.DonatAmount, + streamerID int, + amount int, text string, -) (model.TargetID, error) { +) (int, error) { args := pgx.NamedArgs{ "streamer_id": streamerID, "amount": amount, @@ -36,12 +36,12 @@ func (targetRepo *RepoTarget) CreateTarget( slog.Error(err.Error()) return 0, err } - return model.TargetID(targetID.(int)), nil + return targetID.(int), nil } func (targetRepo *RepoTarget) GetAllTarget( ctx context.Context, - streamerID model.StreamerID, + streamerID int, ) ([]*model.Target, error) { args := pgx.NamedArgs{ "streamer_id": streamerID, @@ -65,8 +65,8 @@ func (targetRepo *RepoTarget) GetAllTarget( func (targetRepo *RepoTarget) AddAmountToTarget( ctx context.Context, - targetID model.TargetID, - amount model.DonatAmount, + targetID int, + amount int, ) error { args := pgx.NamedArgs{ "target_id": targetID, diff --git a/internal/service/donat/donat.go b/internal/service/donat/donat.go index f66903b..05ca63a 100644 --- a/internal/service/donat/donat.go +++ b/internal/service/donat/donat.go @@ -111,11 +111,21 @@ func (donatService *ServiceDonat) CreateDonat( return api.CreatePaymentResponse{}, err } -func (donatService *ServiceDonat) GetDonatByStreamerID( +func (donatService *ServiceDonat) GetDonatsByStreamerID( ctx context.Context, - streamerID model.StreamerID, + streamerID int, + page int, + limit int, ) ([]*model.Donat, error) { - donats, err := donatService.donatRepo.GetDonatByStreamerID(ctx, streamerID) + donats, err := donatService.donatRepo.GetDonatsByStreamerID( + ctx, + streamerID, + page, + limit, + ) + if len(donats) == 0 { + return []*model.Donat{}, nil + } if err != nil { slog.Error(err.Error()) return nil, err @@ -125,7 +135,7 @@ func (donatService *ServiceDonat) GetDonatByStreamerID( func (donatService *ServiceDonat) GetDonatByOrderID( ctx context.Context, - orderID model.OrderID, + orderID string, ) (*model.Donat, error) { donat, err := donatService.donatRepo.GetDonatByOrderID(ctx, orderID) if err != nil { @@ -137,7 +147,7 @@ func (donatService *ServiceDonat) GetDonatByOrderID( func (donatService *ServiceDonat) MarkDonatPaid( ctx context.Context, - orderID model.OrderID, + orderID string, ) error { err := donatService.donatRepo.MarkDonatPaid( ctx, @@ -152,7 +162,7 @@ func (donatService *ServiceDonat) MarkDonatPaid( func (donatService *ServiceDonat) MarkDonatView( ctx context.Context, - donatID model.DonatID, + donatID int, ) error { err := donatService.donatRepo.MarkDonatView( ctx, @@ -167,7 +177,7 @@ func (donatService *ServiceDonat) MarkDonatView( func (donatService *ServiceDonat) GetInnerDonatPage( ctx context.Context, - streamerID model.StreamerID, + streamerID int, ) (model.InnerDonatePageResponse, error) { // Получаем данные страницы доната из репозитория donatePage, err := donatService.donatRepo.GetDonatPage(ctx, streamerID) @@ -505,3 +515,23 @@ func (donatService *ServiceDonat) GetDonatModeration( return donation, nil } + +func (donatService *ServiceDonat) ModerateDonation( + ctx context.Context, + donatID int, + streamerID int, + updateModel model.ModerationDonat, +) error { + err := donatService.donatRepo.ModerateDonation( + ctx, + donatID, + streamerID, + updateModel, + ) + + if err != nil { + slog.Error("Failed to update donat", "error", err) + return err + } + return nil +} diff --git a/internal/service/target/target.go b/internal/service/target/target.go index 1b33c04..fbaa59c 100644 --- a/internal/service/target/target.go +++ b/internal/service/target/target.go @@ -26,10 +26,10 @@ type ServiceTarget struct { func (targetService *ServiceTarget) CreateTarget( ctx context.Context, - streamerID model.StreamerID, - amount model.DonatAmount, + streamerID int, + amount int, text string, -) (model.TargetID, error) { +) (int, error) { targetID, err := targetService.targetRepo.CreateTarget(ctx, streamerID, amount, text) if err != nil { slog.Error(err.Error()) @@ -40,7 +40,7 @@ func (targetService *ServiceTarget) CreateTarget( func (targetService *ServiceTarget) GetAllTarget( ctx context.Context, - streamerID model.StreamerID, + streamerID int, ) ([]*model.Target, error) { targets, err := targetService.targetRepo.GetAllTarget(ctx, streamerID) if err != nil { @@ -53,8 +53,8 @@ func (targetService *ServiceTarget) GetAllTarget( func (targetService *ServiceTarget) AddAmountToTarget( ctx context.Context, - targetID model.TargetID, - amount model.DonatAmount, + targetID int, + amount int, ) error { err := targetService.targetRepo.AddAmountToTarget(ctx, targetID, amount) if err != nil {