add filers for create in update donate page

This commit is contained in:
harold 2025-02-28 14:01:53 +05:00
parent 86e8341f59
commit 447dd1d6a9
11 changed files with 194 additions and 35 deletions

View File

@ -53,7 +53,13 @@ func main() {
// SERVICES
widgetService := WidgetService.New(widgetRepo, authClient)
donatService := DonatService.New(donatRepo, widgetRepo, paymentClient, authClient)
donatService := DonatService.New(
donatRepo,
widgetRepo,
paymentClient,
authClient,
storage,
)
targetService := TargetService.New(targetRepo, authClient)
http.NewApp(

View File

@ -4,6 +4,7 @@ import (
"bytes"
"donat-widget/internal/model"
"io"
"mime/multipart"
"os"
"path/filepath"
)
@ -28,16 +29,18 @@ func NewLocalStorage(basePath string) *LocalStorage {
}
func (ls *LocalStorage) Upload(
file model.UploadFile,
file *multipart.FileHeader,
filename string,
size int64,
collection string,
) (model.FileID, error) {
// Создаем путь для коллекции, если он не существует
collectionPath := filepath.Join(ls.basePath, collection)
if err := os.MkdirAll(collectionPath, os.ModePerm); err != nil {
return "error", err
}
// Создаем путь для файла
filePath := filepath.Join(collectionPath, filename)
f, err := os.Create(filePath)
if err != nil {
@ -45,17 +48,26 @@ func (ls *LocalStorage) Upload(
}
defer f.Close()
_, err = io.Copy(f, *file)
// Открываем исходный файл для чтения
srcFile, err := file.Open()
if err != nil {
return "error opening file", err
}
defer srcFile.Close()
// Копируем содержимое файла
_, err = io.Copy(f, srcFile)
if err != nil {
return "error copy", err
}
// Возвращаем идентификатор файла
return model.FileID(filename), nil
}
func (ls *LocalStorage) Download(
FileID model.FileID,
) (model.DownloadFile, error) {
) ([]byte, error) {
filePath := string(FileID)
f, err := os.Open(filePath)
if err != nil {
@ -73,20 +85,31 @@ func (ls *LocalStorage) Download(
}
func (ls *LocalStorage) Update(
file model.UploadFile,
file *multipart.FileHeader,
fileID model.FileID,
filename string,
size int64,
collection string,
) error {
// Получаем путь для хранения файла
filePath := string(fileID)
// Создаем новый файл
f, err := os.Create(filePath)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, *file)
// Открываем файл из multipart.FileHeader
srcFile, err := file.Open()
if err != nil {
return err
}
defer srcFile.Close()
// Копируем содержимое из исходного файла в новый файл
_, err = io.Copy(f, srcFile)
if err != nil {
return err
}

View File

@ -3,8 +3,8 @@ package donat
import (
"context"
"donat-widget/internal/model"
"donat-widget/pkg/validator"
"donat-widget/pkg/custom_response"
"donat-widget/pkg/validator"
"fmt"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
@ -125,6 +125,7 @@ func MarkDonatView(donatService model.DonatService) echo.HandlerFunc {
// @Tags Donate
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} model.InnerDonatePageResponse "Current donate page state"
// @Failure 400 {object} echo.HTTPError "Bad request"
// @Failure 401 {object} echo.HTTPError "Unauthorized or expired token"
@ -159,7 +160,7 @@ func GetInnerDonatePage(donatService model.DonatService) echo.HandlerFunc {
// @Failure 400 {object} echo.HTTPError "Bad request"
// @Failure 401 {object} echo.HTTPError "Unauthorized or expired token"
// @Failure 422 {object} echo.HTTPError "Validation error"
// @Router /outer-donate-page/:streamer-login [get]
// @Router /outer-donate-page/{streamer-login} [get]
func GetOuterDonatePage(donatService model.DonatService) echo.HandlerFunc {
return func(request echo.Context) error {
ctx := context.Background()
@ -181,8 +182,10 @@ func GetOuterDonatePage(donatService model.DonatService) echo.HandlerFunc {
// @Tags Donate
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body model.UpdateDonatPage true "Update fields"
// @Param background formData file false "Background image"
// @Param head-img formData file false "Head image"
// @Success 200 {string} string "Donat page updated successfully"
// @Failure 400 {object} echo.HTTPError "Bad request"
// @Failure 401 {object} echo.HTTPError "Unauthorized or expired token"
@ -190,31 +193,41 @@ func GetOuterDonatePage(donatService model.DonatService) echo.HandlerFunc {
// @Router /donat-page [patch]
func UpdateDonatePage(donatService model.DonatService) echo.HandlerFunc {
return func(request echo.Context) error {
ctx := context.Background()
var body model.UpdateDonatPage
err := validator.ParseAndValidate(&body, request)
if err != nil {
slog.Error(err.Error())
return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity")
}
form, err := request.MultipartForm()
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 {
slog.Error(err.Error())
return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity")
background = nil
}
headImg, err := request.FormFile("head_img")
if err != nil {
headImg = nil
}
if form != nil {
if backgroundFiles, ok := form.File["background"]; ok && len(backgroundFiles) > 0 {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to save background")
}
err = donatService.UpdateDonatePage(
ctx,
model.StreamerID(authData.AccountID),
body,
background,
headImg,
)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, custom_response.InternalError)
}
// Проверяем и сохраняем avatar, если он передан
if avatarFiles, ok := form.File["avatar"]; ok && len(avatarFiles) > 0 {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to save avatar")
}
return nil
return request.JSON(http.StatusOK, "Success")
}
}

View File

@ -74,6 +74,8 @@ func IncludeDonatHandlers(
server.POST(PREFIX+"/donat/create", CreateDonat(donatService))
server.GET(PREFIX+"/inner-donate-page", GetInnerDonatePage(donatService))
server.GET(PREFIX+"/outer-donate-page/:streamer-login", GetOuterDonatePage(donatService))
server.PATCH(PREFIX+"/donat-page", UpdateDonatePage(donatService))
server.GET(PREFIX+"/donat/get/:streamerID", GetDonat(donatService))

View File

@ -17,6 +17,11 @@ const docTemplate = `{
"paths": {
"/donat-page": {
"patch": {
"security": [
{
"BearerAuth": []
}
],
"description": "Update personal streamer donate page.",
"consumes": [
"application/json"
@ -43,6 +48,12 @@ const docTemplate = `{
"description": "Background image",
"name": "background",
"in": "formData"
},
{
"type": "file",
"description": "Head image",
"name": "head-img",
"in": "formData"
}
],
"responses": {
@ -172,6 +183,11 @@ const docTemplate = `{
},
"/inner-donate-page": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Get inner donate page info",
"consumes": [
"application/json"
@ -291,7 +307,7 @@ const docTemplate = `{
}
}
},
"/outer-donate-page": {
"/outer-donate-page/{streamer-login}": {
"get": {
"description": "Get outer donate page info",
"consumes": [
@ -304,6 +320,15 @@ const docTemplate = `{
"Donate"
],
"summary": "Get outer donate page info",
"parameters": [
{
"type": "string",
"description": "Login стримера",
"name": "streamer-login",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "Current donate page state",
@ -457,7 +482,7 @@ const docTemplate = `{
"description": {
"type": "string"
},
"pageBackground": {
"headImg": {
"type": "string"
},
"textAfterDonat": {
@ -479,9 +504,18 @@ const docTemplate = `{
"donat-widget_internal_model.OuterDonatePageResponse": {
"type": "object",
"properties": {
"avatar_url": {
"type": "string"
},
"background_url": {
"type": "string"
},
"description": {
"type": "string"
},
"headImg": {
"type": "string"
},
"login": {
"type": "string"
},

View File

@ -10,6 +10,11 @@
"paths": {
"/donat-page": {
"patch": {
"security": [
{
"BearerAuth": []
}
],
"description": "Update personal streamer donate page.",
"consumes": [
"application/json"
@ -36,6 +41,12 @@
"description": "Background image",
"name": "background",
"in": "formData"
},
{
"type": "file",
"description": "Head image",
"name": "head-img",
"in": "formData"
}
],
"responses": {
@ -165,6 +176,11 @@
},
"/inner-donate-page": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Get inner donate page info",
"consumes": [
"application/json"
@ -284,7 +300,7 @@
}
}
},
"/outer-donate-page": {
"/outer-donate-page/{streamer-login}": {
"get": {
"description": "Get outer donate page info",
"consumes": [
@ -297,6 +313,15 @@
"Donate"
],
"summary": "Get outer donate page info",
"parameters": [
{
"type": "string",
"description": "Login стримера",
"name": "streamer-login",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "Current donate page state",
@ -450,7 +475,7 @@
"description": {
"type": "string"
},
"pageBackground": {
"headImg": {
"type": "string"
},
"textAfterDonat": {
@ -472,9 +497,18 @@
"donat-widget_internal_model.OuterDonatePageResponse": {
"type": "object",
"properties": {
"avatar_url": {
"type": "string"
},
"background_url": {
"type": "string"
},
"description": {
"type": "string"
},
"headImg": {
"type": "string"
},
"login": {
"type": "string"
},

View File

@ -17,7 +17,7 @@ definitions:
type: string
description:
type: string
pageBackground:
headImg:
type: string
textAfterDonat:
type: string
@ -31,8 +31,14 @@ definitions:
type: object
donat-widget_internal_model.OuterDonatePageResponse:
properties:
avatar_url:
type: string
background_url:
type: string
description:
type: string
headImg:
type: string
login:
type: string
online:
@ -119,6 +125,10 @@ paths:
in: formData
name: background
type: file
- description: Head image
in: formData
name: head-img
type: file
produces:
- application/json
responses:
@ -138,6 +148,8 @@ paths:
description: Validation error
schema:
$ref: '#/definitions/echo.HTTPError'
security:
- BearerAuth: []
summary: Update personal streamer donate page.
tags:
- Donate
@ -229,6 +241,8 @@ paths:
description: Validation error
schema:
$ref: '#/definitions/echo.HTTPError'
security:
- BearerAuth: []
summary: Get inner donate page info
tags:
- Donate
@ -285,11 +299,17 @@ paths:
summary: Update donat moderation settings
tags:
- Donate
/outer-donate-page:
/outer-donate-page/{streamer-login}:
get:
consumes:
- application/json
description: Get outer donate page info
parameters:
- description: Login стримера
in: path
name: streamer-login
required: true
type: string
produces:
- application/json
responses:

View File

@ -5,6 +5,7 @@ import (
"donat-widget/internal/model/api"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"mime/multipart"
)
type WidgetService interface {
@ -46,8 +47,13 @@ type DonatService interface {
GetInnerDonatPage(ctx context.Context, streamerID StreamerID) (InnerDonatePageResponse, error)
GetOuterDonatPage(ctx context.Context, streamerLogin string) (OuterDonatePageResponse, error)
UpdateDonatePage(ctx context.Context, streamerID StreamerID, updateModel UpdateDonatPage) error
UpdateDonatePage(
ctx context.Context,
streamerID StreamerID,
updateModel UpdateDonatPage,
background *multipart.FileHeader,
headImg *multipart.FileHeader,
) error
GetVoiceSettings(ctx context.Context, streamerID StreamerID) (VoiceSettingsResponse, error)
UpdateVoiceSettings(ctx context.Context, streamerID StreamerID, updateModel UpdateVoiceSettings) error
@ -90,9 +96,9 @@ type Error interface {
}
type Storage interface {
Upload(file UploadFile, filename string, size int64, collection string) (FileID, error)
Download(FileID FileID) (DownloadFile, error)
Update(file UploadFile, fileID FileID, filename string, size int64, collection string) error
Upload(file *multipart.FileHeader, filename string, size int64, collection string) (FileID, error)
Download(FileID FileID) ([]byte, error)
Update(file *multipart.FileHeader, fileID FileID, filename string, size int64, collection string) error
}
type PaymentClient interface {

View File

@ -18,7 +18,7 @@ type Widgets []*Widget
type WidgetHTML string
type WeedData *goseaweedfs.FilePart
type UploadFile *multipart.File
type UploadFile *multipart.FileHeader
type DownloadFile []byte
type FileID string

View File

@ -6,6 +6,7 @@ import (
"donat-widget/internal/model/api"
"github.com/labstack/echo/v4"
"log/slog"
"mime/multipart"
"net/http"
)
@ -14,6 +15,7 @@ type ServiceDonat struct {
widgetRepo model.WidgetRepo
authClient model.AuthClient
paymentClient model.PaymentClient
storage model.Storage
}
func New(
@ -21,12 +23,14 @@ func New(
widgetRepo model.WidgetRepo,
paymentClient model.PaymentClient,
authClient model.AuthClient,
storage model.Storage,
) *ServiceDonat {
return &ServiceDonat{
donatRepo: donatRepo,
widgetRepo: widgetRepo,
paymentClient: paymentClient,
authClient: authClient,
storage: storage,
}
}
@ -193,8 +197,24 @@ func (donatService *ServiceDonat) UpdateDonatePage(
ctx context.Context,
streamerID model.StreamerID,
updateModel model.UpdateDonatPage,
background *multipart.FileHeader,
headImg *multipart.FileHeader,
) error {
if background != nil {
err := donatService.storage.Update(
background, // ❌ Было &background → ✅ Просто background
model.FileID("some-id"),
"test-filename",
999999,
"hello world",
)
if err != nil {
slog.Error(err.Error())
}
}
return nil
}
func (donatService *ServiceDonat) GetVoiceSettings(

View File

@ -12,6 +12,7 @@ const (
AccountNotFound = "Account not found"
NotVerified2FA = "2FA not verified"
NotExists2FA = "2FA does not exist"
Unauthorized = "Unauthorized"
)
// Success response