add rotuter for update donate page

This commit is contained in:
harold 2025-03-08 17:32:33 +05:00
parent 5f7a18c210
commit d87808531e
12 changed files with 232 additions and 128 deletions

View File

@ -56,15 +56,17 @@ func main() {
// SERVICES // SERVICES
widgetService := WidgetService.New(widgetRepo, authClient, fileRepo, storage) widgetService := WidgetService.New(widgetRepo, authClient, fileRepo, storage)
targetService := TargetService.New(targetRepo, authClient)
fileService := FileService.New(authClient, fileRepo, storage)
donatService := DonatService.New( donatService := DonatService.New(
donatRepo, donatRepo,
widgetRepo, widgetRepo,
paymentClient, paymentClient,
authClient, authClient,
fileRepo,
fileService,
storage, storage,
) )
targetService := TargetService.New(targetRepo, authClient)
fileService := FileService.New(authClient, fileRepo, storage)
http.NewApp( http.NewApp(
db, db,

View File

@ -9,6 +9,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"log/slog" "log/slog"
"mime/multipart"
"net/http" "net/http"
"strconv" "strconv"
) )
@ -177,21 +178,21 @@ func GetOuterDonatePage(donatService model.DonatService) echo.HandlerFunc {
} }
// UpdateDonatePage godoc // UpdateDonatePage godoc
// @Summary Update personal streamer donate page. // @Summary Update personal streamer donate page
// @Description Update personal streamer donate page. // @Description Update personal streamer donate page with optional background and head image files.
// @Tags Donate // @Tags Donate
// @Accept json // @Consumes multipart/form-data
// @Produce json // @Produces json
// @Security BearerAuth // @Security BearerAuth
// @Param request body model.UpdateDonatPage true "Update fields" // @Param metadata formData model.UpdateDonatPage false "Update fields"
// @Param background formData file false "Background image" // @Param background formData file false "Background image"
// @Param head-img formData file false "Head image" // @Param head_img formData file false "Head image"
// @Success 200 {string} string "Donat page updated successfully" // @Success 200 {string} string "Donat page updated successfully"
// @Failure 400 {object} echo.HTTPError "Bad request" // @Failure 400 {object} echo.HTTPError "Bad request"
// @Failure 401 {object} echo.HTTPError "Unauthorized or expired token" // @Failure 401 {object} echo.HTTPError "Unauthorized or expired token"
// @Failure 422 {object} echo.HTTPError "Validation error" // @Failure 422 {object} echo.HTTPError "Validation error"
// @Router /donat-page [patch] // @Router /donat-page [patch]
func UpdateDonatePage(donatService model.DonatService) echo.HandlerFunc { func UpdateDonatePage(donatService model.DonatService, fileService model.FileService) echo.HandlerFunc {
return func(request echo.Context) error { return func(request echo.Context) error {
ctx := context.Background() ctx := context.Background()
@ -203,26 +204,36 @@ func UpdateDonatePage(donatService model.DonatService) echo.HandlerFunc {
} }
authData, err := donatService.CheckToken(request) authData, err := donatService.CheckToken(request)
//if err != nil {
// slog.Error(err.Error())
// return echo.NewHTTPError(http.StatusUnauthorized, custom_response.Unauthorized)
//}
background, err := request.FormFile("background")
if err != nil { if err != nil {
background = nil slog.Error(err.Error())
} return echo.NewHTTPError(http.StatusUnauthorized, custom_response.Unauthorized)
headImg, err := request.FormFile("head_img")
if err != nil {
headImg = nil
} }
bgFile, err := request.FormFile("background")
if err != nil {
bgFile = &multipart.FileHeader{
Filename: "",
Size: 0,
Header: nil,
}
}
headImgFile, err := request.FormFile("head_img")
if err != nil {
headImgFile = &multipart.FileHeader{
Filename: "",
Size: 0,
Header: nil,
}
}
// Передаем файлы только если они были переданы
err = donatService.UpdateDonatePage( err = donatService.UpdateDonatePage(
ctx, ctx,
model.StreamerID(authData.AccountID), authData.AccountID,
body, body,
background, *bgFile,
headImg, *headImgFile,
) )
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, custom_response.InternalError) return echo.NewHTTPError(http.StatusInternalServerError, custom_response.InternalError)

View File

@ -46,7 +46,7 @@ func NewApp(
server.GET(PREFIX+"/docs/*", echoSwagger.WrapHandler) server.GET(PREFIX+"/docs/*", echoSwagger.WrapHandler)
IncludeWidgetHandlers(server, widgetService) IncludeWidgetHandlers(server, widgetService)
IncludeDonatHandlers(server, donatService) IncludeDonatHandlers(server, donatService, fileService)
IncludeTargetHandlers(server, targetService, donatService, authClient) IncludeTargetHandlers(server, targetService, donatService, authClient)
IncludeFileHandlers(server, fileService) IncludeFileHandlers(server, fileService)
@ -67,12 +67,13 @@ func IncludeTargetHandlers(
func IncludeDonatHandlers( func IncludeDonatHandlers(
server *echo.Echo, server *echo.Echo,
donatService model.DonatService, donatService model.DonatService,
fileService model.FileService,
) { ) {
server.POST(PREFIX+"/donat/create", CreateDonat(donatService)) server.POST(PREFIX+"/donat/create", CreateDonat(donatService))
server.GET(PREFIX+"/inner-donate-page", GetInnerDonatePage(donatService)) server.GET(PREFIX+"/inner-donate-page", GetInnerDonatePage(donatService))
server.GET(PREFIX+"/outer-donate-page/:streamer-login", GetOuterDonatePage(donatService)) server.GET(PREFIX+"/outer-donate-page/:streamer-login", GetOuterDonatePage(donatService))
server.PATCH(PREFIX+"/donat-page", UpdateDonatePage(donatService)) server.PATCH(PREFIX+"/donat-page", UpdateDonatePage(donatService, fileService))
server.GET(PREFIX+"/donat/get/:streamerID", GetDonat(donatService)) server.GET(PREFIX+"/donat/get/:streamerID", GetDonat(donatService))

View File

@ -22,26 +22,35 @@ const docTemplate = `{
"BearerAuth": [] "BearerAuth": []
} }
], ],
"description": "Update personal streamer donate page.", "description": "Update personal streamer donate page with optional background and head image files.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [ "tags": [
"Donate" "Donate"
], ],
"summary": "Update personal streamer donate page.", "summary": "Update personal streamer donate page",
"parameters": [ "parameters": [
{ {
"description": "Update fields", "type": "string",
"name": "request", "example": "A great donation page",
"in": "body", "name": "description",
"required": true, "in": "formData"
"schema": { },
"$ref": "#/definitions/donat-widget_internal_model.UpdateDonatPage" {
} "type": "string",
"example": "#13161E",
"name": "page_background",
"in": "formData"
},
{
"type": "boolean",
"example": true,
"name": "profile_avatar",
"in": "formData"
},
{
"type": "string",
"example": "Thank you for your support!",
"name": "text_after_donat",
"in": "formData"
}, },
{ {
"type": "file", "type": "file",
@ -52,7 +61,7 @@ const docTemplate = `{
{ {
"type": "file", "type": "file",
"description": "Head image", "description": "Head image",
"name": "head-img", "name": "head_img",
"in": "formData" "in": "formData"
} }
], ],
@ -839,6 +848,9 @@ const docTemplate = `{
"created_at": { "created_at": {
"type": "string" "type": "string"
}, },
"entity": {
"type": "string"
},
"extension": { "extension": {
"type": "string" "type": "string"
}, },
@ -1020,23 +1032,6 @@ const docTemplate = `{
} }
} }
}, },
"donat-widget_internal_model.UpdateDonatPage": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"page_background": {
"type": "string"
},
"profile_avatar": {
"type": "boolean"
},
"text_after_donat": {
"type": "string"
}
}
},
"donat-widget_internal_model.UpdateFilterSettings": { "donat-widget_internal_model.UpdateFilterSettings": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -15,26 +15,35 @@
"BearerAuth": [] "BearerAuth": []
} }
], ],
"description": "Update personal streamer donate page.", "description": "Update personal streamer donate page with optional background and head image files.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [ "tags": [
"Donate" "Donate"
], ],
"summary": "Update personal streamer donate page.", "summary": "Update personal streamer donate page",
"parameters": [ "parameters": [
{ {
"description": "Update fields", "type": "string",
"name": "request", "example": "A great donation page",
"in": "body", "name": "description",
"required": true, "in": "formData"
"schema": { },
"$ref": "#/definitions/donat-widget_internal_model.UpdateDonatPage" {
} "type": "string",
"example": "#13161E",
"name": "page_background",
"in": "formData"
},
{
"type": "boolean",
"example": true,
"name": "profile_avatar",
"in": "formData"
},
{
"type": "string",
"example": "Thank you for your support!",
"name": "text_after_donat",
"in": "formData"
}, },
{ {
"type": "file", "type": "file",
@ -45,7 +54,7 @@
{ {
"type": "file", "type": "file",
"description": "Head image", "description": "Head image",
"name": "head-img", "name": "head_img",
"in": "formData" "in": "formData"
} }
], ],
@ -832,6 +841,9 @@
"created_at": { "created_at": {
"type": "string" "type": "string"
}, },
"entity": {
"type": "string"
},
"extension": { "extension": {
"type": "string" "type": "string"
}, },
@ -1013,23 +1025,6 @@
} }
} }
}, },
"donat-widget_internal_model.UpdateDonatPage": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"page_background": {
"type": "string"
},
"profile_avatar": {
"type": "boolean"
},
"text_after_donat": {
"type": "string"
}
}
},
"donat-widget_internal_model.UpdateFilterSettings": { "donat-widget_internal_model.UpdateFilterSettings": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -38,6 +38,8 @@ definitions:
properties: properties:
created_at: created_at:
type: string type: string
entity:
type: string
extension: extension:
type: string type: string
file_link: file_link:
@ -167,17 +169,6 @@ definitions:
online: online:
type: string type: string
type: object type: object
donat-widget_internal_model.UpdateDonatPage:
properties:
description:
type: string
page_background:
type: string
profile_avatar:
type: boolean
text_after_donat:
type: string
type: object
donat-widget_internal_model.UpdateFilterSettings: donat-widget_internal_model.UpdateFilterSettings:
properties: properties:
add_words: add_words:
@ -258,26 +249,33 @@ info:
paths: paths:
/donat-page: /donat-page:
patch: patch:
consumes: description: Update personal streamer donate page with optional background and
- application/json head image files.
description: Update personal streamer donate page.
parameters: parameters:
- description: Update fields - example: A great donation page
in: body in: formData
name: request name: description
required: true type: string
schema: - example: '#13161E'
$ref: '#/definitions/donat-widget_internal_model.UpdateDonatPage' in: formData
name: page_background
type: string
- example: true
in: formData
name: profile_avatar
type: boolean
- example: Thank you for your support!
in: formData
name: text_after_donat
type: string
- description: Background image - description: Background image
in: formData in: formData
name: background name: background
type: file type: file
- description: Head image - description: Head image
in: formData in: formData
name: head-img name: head_img
type: file type: file
produces:
- application/json
responses: responses:
"200": "200":
description: Donat page updated successfully description: Donat page updated successfully
@ -297,7 +295,7 @@ paths:
$ref: '#/definitions/echo.HTTPError' $ref: '#/definitions/echo.HTTPError'
security: security:
- BearerAuth: [] - BearerAuth: []
summary: Update personal streamer donate page. summary: Update personal streamer donate page
tags: tags:
- Donate - Donate
/files: /files:

View File

@ -85,10 +85,10 @@ type DonatService interface {
GetOuterDonatPage(ctx context.Context, streamerLogin string) (OuterDonatePageResponse, error) GetOuterDonatPage(ctx context.Context, streamerLogin string) (OuterDonatePageResponse, error)
UpdateDonatePage( UpdateDonatePage(
ctx context.Context, ctx context.Context,
streamerID StreamerID, streamerID int,
updateModel UpdateDonatPage, updateModel UpdateDonatPage,
background *multipart.FileHeader, background multipart.FileHeader,
headImg *multipart.FileHeader, headImg multipart.FileHeader,
) error ) error
GetVoiceSettings(ctx context.Context, streamerID StreamerID) (VoiceSettingsResponse, error) GetVoiceSettings(ctx context.Context, streamerID StreamerID) (VoiceSettingsResponse, error)
UpdateVoiceSettings(ctx context.Context, streamerID StreamerID, updateModel UpdateVoiceSettings) error UpdateVoiceSettings(ctx context.Context, streamerID StreamerID, updateModel UpdateVoiceSettings) error
@ -111,6 +111,15 @@ type DonatRepo interface {
GetDonatPage(ctx context.Context, streamerID StreamerID) (DonatePage, error) GetDonatPage(ctx context.Context, streamerID StreamerID) (DonatePage, error)
GetDonatPageByLogin(ctx context.Context, streamerLogin string) (DonatePage, error) GetDonatPageByLogin(ctx context.Context, streamerLogin string) (DonatePage, error)
UpdateDonatePage(
ctx context.Context,
streamerID int,
backgroundFileID *string,
headImgFileID *string,
description *string,
textAfterDonation *string,
) error
} }
type TargetService interface { type TargetService interface {

View File

@ -157,10 +157,10 @@ type VoiceLanguage struct {
} }
type UpdateDonatPage struct { type UpdateDonatPage struct {
ProfileAvatar bool `json:"profile_avatar"` ProfileAvatar *bool `json:"profile_avatar,omitempty" form:"profile_avatar" example:"true" description:"Indicates whether the profile avatar is displayed"`
Description string `json:"description"` Description *string `json:"description,omitempty" form:"description" example:"A great donation page" description:"Description of the donation page"`
TextAfterDonat string `json:"text_after_donat"` TextAfterDonat *string `json:"text_after_donat,omitempty" form:"text_after_donat" example:"Thank you for your support!" description:"Text displayed after a donation"`
PageBackground string `json:"page_background"` PageBackground *string `json:"page_background,omitempty" form:"page_background" example:"#13161E" description:"Color code"`
} }
type VoiceSettingsResponse struct { type VoiceSettingsResponse struct {

View File

@ -113,9 +113,9 @@ WHERE w.streamer_id = (@streamer_id);
` `
var AddNewFile = ` var AddNewFile = `
INSERT INTO files (streamer_id, file_name, file_type, extension) INSERT INTO files (streamer_id, file_name, file_type, extension, entity, size)
VALUES VALUES
(@streamer_id, @file_name, @file_type, @extension) (@streamer_id, @file_name, @file_type, @extension, @entity, @size)
RETURNING id; RETURNING id;
` `
@ -157,3 +157,14 @@ WHERE id = @id;
var GetWidgetById = ` var GetWidgetById = `
SELECT id FROM widgets WHERE id = (@widget_id) AND streamer_id = (@streamer_id); SELECT id FROM widgets WHERE id = (@widget_id) AND streamer_id = (@streamer_id);
` `
var UpdateDonatePage = `
UPDATE donate_pages
SET
background_img = COALESCE(@background_img, background_img),
head_img = COALESCE(@head_img, head_img),
description = COALESCE(@description, description),
text_after_donat = COALESCE(@text_after_donation, text_after_donat)
WHERE streamer_id = @streamer_id
RETURNING *;
`

View File

@ -184,3 +184,37 @@ func (repoDonat *RepoDonat) GetDonatPageByLogin(
return *donatePage[0], nil return *donatePage[0], nil
} }
func (repoDonat *RepoDonat) UpdateDonatePage(
ctx context.Context,
streamerID int,
backgroundFileID *string,
headImgFileID *string,
description *string,
textAfterDonation *string,
) error {
args := pgx.NamedArgs{
"streamer_id": streamerID,
}
if backgroundFileID != nil {
args["background_img"] = *backgroundFileID
}
if headImgFileID != nil {
args["head_img"] = *headImgFileID
}
if description != nil {
args["description"] = *description
}
if textAfterDonation != nil {
args["text_after_donat"] = *textAfterDonation
}
err := repoDonat.db.Update(ctx, sql.UpdateDonatePage, args)
if err != nil {
slog.Error(err.Error())
return err
}
return nil
}

View File

@ -15,6 +15,8 @@ type ServiceDonat struct {
widgetRepo model.WidgetRepo widgetRepo model.WidgetRepo
authClient model.AuthClient authClient model.AuthClient
paymentClient model.PaymentClient paymentClient model.PaymentClient
fileRepo model.FileRepo
fileService model.FileService
storage model.Storage storage model.Storage
} }
@ -23,6 +25,8 @@ func New(
widgetRepo model.WidgetRepo, widgetRepo model.WidgetRepo,
paymentClient model.PaymentClient, paymentClient model.PaymentClient,
authClient model.AuthClient, authClient model.AuthClient,
fileRepo model.FileRepo,
fileService model.FileService,
storage model.Storage, storage model.Storage,
) *ServiceDonat { ) *ServiceDonat {
return &ServiceDonat{ return &ServiceDonat{
@ -30,6 +34,8 @@ func New(
widgetRepo: widgetRepo, widgetRepo: widgetRepo,
paymentClient: paymentClient, paymentClient: paymentClient,
authClient: authClient, authClient: authClient,
fileRepo: fileRepo,
fileService: fileService,
storage: storage, storage: storage,
} }
} }
@ -196,14 +202,55 @@ func (donatService *ServiceDonat) GetOuterDonatPage(
func (donatService *ServiceDonat) UpdateDonatePage( func (donatService *ServiceDonat) UpdateDonatePage(
ctx context.Context, ctx context.Context,
streamerID model.StreamerID, streamerID int,
updateModel model.UpdateDonatPage, updateModel model.UpdateDonatPage,
background *multipart.FileHeader, background multipart.FileHeader,
headImg *multipart.FileHeader, headImg multipart.FileHeader,
) error { ) error {
var backgroundFileID *string
var headImgFileID *string
if background.Size > 0 {
fileID, err := donatService.fileService.AddNewFile(
ctx,
background,
streamerID,
"donat_page",
)
if err != nil {
slog.Error(err.Error())
return err
}
backgroundFileID = &fileID
}
if headImg.Size > 0 {
fileID, err := donatService.fileService.AddNewFile(
ctx,
headImg,
streamerID,
"donat_page",
)
if err != nil {
slog.Error(err.Error())
return err
}
headImgFileID = &fileID
}
err := donatService.donatRepo.UpdateDonatePage(
ctx,
streamerID,
backgroundFileID,
headImgFileID,
updateModel.Description,
updateModel.TextAfterDonat,
)
if err != nil {
slog.Error(err.Error())
return err
}
return nil return nil
} }
func (donatService *ServiceDonat) GetVoiceSettings( func (donatService *ServiceDonat) GetVoiceSettings(

View File

@ -9,6 +9,7 @@ CREATE TABLE IF NOT EXISTS files (
extension VARCHAR(10) NOT NULL, extension VARCHAR(10) NOT NULL,
streamer_id INTEGER NOT NULL, streamer_id INTEGER NOT NULL,
entity VARCHAR(50) NOT NULL DEFAULT 'widget', entity VARCHAR(50) NOT NULL DEFAULT 'widget',
size FLOAT NOT NULL DEFAULT 10,
created_at TIMESTAMP DEFAULT now() created_at TIMESTAMP DEFAULT now()
); );
CREATE TABLE IF NOT EXISTS widgets ( CREATE TABLE IF NOT EXISTS widgets (