add fix for widget and add rouer for create donat

This commit is contained in:
harold 2025-03-09 18:15:11 +05:00
parent bf74330beb
commit f5e143c044
14 changed files with 393 additions and 74 deletions

View File

@ -3,10 +3,10 @@ package donat
import ( import (
"context" "context"
"donat-widget/internal/model" "donat-widget/internal/model"
_ "donat-widget/internal/model/api"
"donat-widget/pkg/custom_response" "donat-widget/pkg/custom_response"
"donat-widget/pkg/validator" "donat-widget/pkg/validator"
"fmt" "fmt"
"github.com/google/uuid"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"log/slog" "log/slog"
"mime/multipart" "mime/multipart"
@ -14,36 +14,39 @@ import (
"strconv" "strconv"
) )
// CreateDonat godoc
// @Summary Create donat
// @Description Create donat
// @Tags Donate
// @Accept json
// @Produce json
// @Param streamer-login path string true "Login стримера"
// @Param request body model.CreateDonatBody true "Create donat body json"
// @Success 200 {object} api.CreatePaymentResponse "Donat page 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/{streamer-login} [post]
func CreateDonat(donatService model.DonatService) echo.HandlerFunc { func CreateDonat(donatService model.DonatService) echo.HandlerFunc {
type CreateDonatBody struct {
StreamerID model.StreamerID `json:"streamerID"`
TargetID model.TargetID `json:"targetID"`
Amount model.DonatAmount `json:"amount"`
Text string `json:"text"`
DonatUser string `json:"donatUser"`
}
return func(request echo.Context) error { return func(request echo.Context) error {
ctx := context.Background() ctx := context.Background()
var body CreateDonatBody var body model.CreateDonatBody
if err := request.Bind(&body); err != nil {
err := validator.ParseAndValidate(&body, request)
if err != nil {
slog.Error(err.Error()) slog.Error(err.Error())
return request.JSON(http.StatusInternalServerError, err.Error()) return echo.NewHTTPError(http.StatusUnprocessableEntity, "Unprocessable Entity")
}
if err := request.Validate(&body); err != nil {
slog.Error(err.Error())
return request.JSON(http.StatusInternalServerError, err.Error())
} }
orderID := model.OrderID(uuid.New().String()) streamerLogin := request.Param("streamer-login")
order, err := donatService.CreateDonat( order, err := donatService.CreateDonat(
ctx, ctx,
body.StreamerID, streamerLogin,
orderID,
body.TargetID,
body.Amount,
body.Text, body.Text,
body.DonatUser, body.DonatUser,
body.TargetID,
body.Amount,
) )
if err != nil { if err != nil {
return request.JSON(http.StatusInternalServerError, err.Error()) return request.JSON(http.StatusInternalServerError, err.Error())

View File

@ -247,7 +247,7 @@ func UpdateWidget(widgetService model.WidgetService) echo.HandlerFunc {
// slog.Info("set " + mediaType + " file successfully") // slog.Info("set " + mediaType + " file successfully")
// return request.String(200, "File successfully uploaded") // return request.String(200, "File successfully uploaded")
// } // }
//} //}e
// //
//func GetMediaFile(widgetService model.WidgetService) echo.HandlerFunc { //func GetMediaFile(widgetService model.WidgetService) echo.HandlerFunc {
// return func(request echo.Context) error { // return func(request echo.Context) error {

View File

@ -69,7 +69,7 @@ func IncludeDonatHandlers(
donatService model.DonatService, donatService model.DonatService,
fileService model.FileService, fileService model.FileService,
) { ) {
server.POST(PREFIX+"/donat/create", CreateDonat(donatService)) server.POST(PREFIX+"/donat/:streamer-login", 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))

View File

@ -93,6 +93,65 @@ const docTemplate = `{
} }
} }
}, },
"/donat/{streamer-login}": {
"post": {
"description": "Create donat",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Donate"
],
"summary": "Create donat",
"parameters": [
{
"type": "string",
"description": "Login стримера",
"name": "streamer-login",
"in": "path",
"required": true
},
{
"description": "Create donat body json",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/donat-widget_internal_model.CreateDonatBody"
}
}
],
"responses": {
"200": {
"description": "Donat page updated successfully",
"schema": {
"$ref": "#/definitions/donat-widget_internal_model_api.CreatePaymentResponse"
}
},
"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"
}
}
}
}
},
"/files": { "/files": {
"post": { "post": {
"security": [ "security": [
@ -827,6 +886,23 @@ const docTemplate = `{
} }
}, },
"definitions": { "definitions": {
"donat-widget_internal_model.CreateDonatBody": {
"type": "object",
"properties": {
"amount": {
"type": "integer"
},
"donatUser": {
"type": "string"
},
"targetID": {
"type": "integer"
},
"text": {
"type": "string"
}
}
},
"donat-widget_internal_model.CreateWidgetBody": { "donat-widget_internal_model.CreateWidgetBody": {
"type": "object", "type": "object",
"required": [ "required": [
@ -990,6 +1066,11 @@ const docTemplate = `{
"format": "int64", "format": "int64",
"example": 100 "example": 100
}, },
"name": {
"type": "string",
"format": "string",
"example": "Мой виджет 10"
},
"streamer_id": { "streamer_id": {
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
@ -1237,6 +1318,35 @@ const docTemplate = `{
} }
} }
}, },
"donat-widget_internal_model_api.CreatePaymentResponse": {
"type": "object",
"properties": {
"Amount": {
"type": "integer"
},
"ErrorCode": {
"type": "string"
},
"OrderId": {
"type": "string"
},
"PaymentId": {
"type": "string"
},
"PaymentURL": {
"type": "string"
},
"Status": {
"type": "string"
},
"Success": {
"type": "boolean"
},
"TerminalKey": {
"type": "string"
}
}
},
"echo.HTTPError": { "echo.HTTPError": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -86,6 +86,65 @@
} }
} }
}, },
"/donat/{streamer-login}": {
"post": {
"description": "Create donat",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Donate"
],
"summary": "Create donat",
"parameters": [
{
"type": "string",
"description": "Login стримера",
"name": "streamer-login",
"in": "path",
"required": true
},
{
"description": "Create donat body json",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/donat-widget_internal_model.CreateDonatBody"
}
}
],
"responses": {
"200": {
"description": "Donat page updated successfully",
"schema": {
"$ref": "#/definitions/donat-widget_internal_model_api.CreatePaymentResponse"
}
},
"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"
}
}
}
}
},
"/files": { "/files": {
"post": { "post": {
"security": [ "security": [
@ -820,6 +879,23 @@
} }
}, },
"definitions": { "definitions": {
"donat-widget_internal_model.CreateDonatBody": {
"type": "object",
"properties": {
"amount": {
"type": "integer"
},
"donatUser": {
"type": "string"
},
"targetID": {
"type": "integer"
},
"text": {
"type": "string"
}
}
},
"donat-widget_internal_model.CreateWidgetBody": { "donat-widget_internal_model.CreateWidgetBody": {
"type": "object", "type": "object",
"required": [ "required": [
@ -983,6 +1059,11 @@
"format": "int64", "format": "int64",
"example": 100 "example": 100
}, },
"name": {
"type": "string",
"format": "string",
"example": "Мой виджет 10"
},
"streamer_id": { "streamer_id": {
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
@ -1230,6 +1311,35 @@
} }
} }
}, },
"donat-widget_internal_model_api.CreatePaymentResponse": {
"type": "object",
"properties": {
"Amount": {
"type": "integer"
},
"ErrorCode": {
"type": "string"
},
"OrderId": {
"type": "string"
},
"PaymentId": {
"type": "string"
},
"PaymentURL": {
"type": "string"
},
"Status": {
"type": "string"
},
"Success": {
"type": "boolean"
},
"TerminalKey": {
"type": "string"
}
}
},
"echo.HTTPError": { "echo.HTTPError": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -1,5 +1,16 @@
basePath: /api/widget basePath: /api/widget
definitions: definitions:
donat-widget_internal_model.CreateDonatBody:
properties:
amount:
type: integer
donatUser:
type: string
targetID:
type: integer
text:
type: string
type: object
donat-widget_internal_model.CreateWidgetBody: donat-widget_internal_model.CreateWidgetBody:
properties: properties:
audio: audio:
@ -121,6 +132,10 @@ definitions:
example: 100 example: 100
format: int64 format: int64
type: integer type: integer
name:
example: Мой виджет 10
format: string
type: string
streamer_id: streamer_id:
example: 1001 example: 1001
format: int64 format: int64
@ -290,6 +305,25 @@ definitions:
$ref: '#/definitions/donat-widget_internal_model.GetWidgetDb' $ref: '#/definitions/donat-widget_internal_model.GetWidgetDb'
type: array type: array
type: object type: object
donat-widget_internal_model_api.CreatePaymentResponse:
properties:
Amount:
type: integer
ErrorCode:
type: string
OrderId:
type: string
PaymentId:
type: string
PaymentURL:
type: string
Status:
type: string
Success:
type: boolean
TerminalKey:
type: string
type: object
echo.HTTPError: echo.HTTPError:
properties: properties:
message: {} message: {}
@ -351,6 +385,45 @@ paths:
summary: Update personal streamer donate page summary: Update personal streamer donate page
tags: tags:
- Donate - Donate
/donat/{streamer-login}:
post:
consumes:
- application/json
description: Create donat
parameters:
- description: Login стримера
in: path
name: streamer-login
required: true
type: string
- description: Create donat body json
in: body
name: request
required: true
schema:
$ref: '#/definitions/donat-widget_internal_model.CreateDonatBody'
produces:
- application/json
responses:
"200":
description: Donat page updated successfully
schema:
$ref: '#/definitions/donat-widget_internal_model_api.CreatePaymentResponse'
"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'
summary: Create donat
tags:
- Donate
/files: /files:
post: post:
consumes: consumes:

View File

@ -73,7 +73,7 @@ type WidgetRepo interface {
type DonatService interface { type DonatService interface {
CheckToken(request echo.Context) (api.CheckTokenResponse, error) CheckToken(request echo.Context) (api.CheckTokenResponse, error)
CreateDonat(ctx context.Context, streamerID StreamerID, orderID OrderID, targetID TargetID, amount DonatAmount, text string, donatUser string) (api.CreatePaymentResponse, error) CreateDonat(ctx context.Context, streamerLogin, text, donatUser string, targetID, amount int) (api.CreatePaymentResponse, error)
GetDonatByStreamerID(ctx context.Context, streamerID StreamerID) ([]*Donat, error) GetDonatByStreamerID(ctx context.Context, streamerID StreamerID) ([]*Donat, error)
GetDonatByOrderID(ctx context.Context, orderID OrderID) (*Donat, error) GetDonatByOrderID(ctx context.Context, orderID OrderID) (*Donat, error)
@ -101,7 +101,16 @@ type DonatService interface {
} }
type DonatRepo interface { type DonatRepo interface {
CreateDonat(ctx context.Context, streamerID StreamerID, widgetID WidgetID, orderID OrderID, targetID TargetID, amount DonatAmount, text string, donatUser string) error CreateDonat(
ctx context.Context,
streamerID int,
targetID int,
widgetID int,
orderID uuid.UUID,
amount int,
text string,
donatUser string,
) error
GetDonatByStreamerID(ctx context.Context, streamerID StreamerID) ([]*Donat, error) GetDonatByStreamerID(ctx context.Context, streamerID StreamerID) ([]*Donat, error)
GetDonatByOrderID(ctx context.Context, orderID OrderID) (*Donat, error) GetDonatByOrderID(ctx context.Context, orderID OrderID) (*Donat, error)
@ -166,7 +175,7 @@ type Storage interface {
} }
type PaymentClient interface { type PaymentClient interface {
CreatePayment(streamerID StreamerID, amount DonatAmount, orderID OrderID) (api.CreatePaymentResponse, error) CreatePayment(streamerID int, amount int, orderID uuid.UUID) (api.CreatePaymentResponse, error)
} }
type Db interface { type Db interface {
Insert(ctx context.Context, query string, args ...interface{}) (any, error) Insert(ctx context.Context, query string, args ...interface{}) (any, error)

View File

@ -21,6 +21,7 @@ type GetWidgetDb struct {
ID int `db:"id" json:"id" example:"1" format:"int64" description:"Unique identifier of the widget"` ID int `db:"id" json:"id" example:"1" format:"int64" description:"Unique identifier of the widget"`
StreamerID int `db:"streamer_id" json:"streamer_id" example:"1001" format:"int64" description:"ID of the streamer"` StreamerID int `db:"streamer_id" json:"streamer_id" example:"1001" format:"int64" description:"ID of the streamer"`
TemplateID int `db:"template_id" json:"template_id" example:"5" format:"int64" description:"ID of the template"` TemplateID int `db:"template_id" json:"template_id" example:"5" format:"int64" description:"ID of the template"`
Name string `db:"name" json:"name" example:"Мой виджет 10" format:"string" description:"Имя виджета"`
Duration int `db:"duration" json:"duration" example:"30" format:"int64" description:"Duration of the widget"` Duration int `db:"duration" json:"duration" example:"30" format:"int64" description:"Duration of the widget"`
MinAmount int `db:"min_amount" json:"min_amount" example:"100" format:"int64" description:"Minimum donation amount"` MinAmount int `db:"min_amount" json:"min_amount" example:"100" format:"int64" description:"Minimum donation amount"`
MaxAmount int `db:"max_amount" json:"max_amount" example:"1000" format:"int64" description:"Maximum donation amount"` MaxAmount int `db:"max_amount" json:"max_amount" example:"1000" format:"int64" description:"Maximum donation amount"`
@ -68,8 +69,7 @@ type Donat struct {
DonatUser string `db:"donat_user"` DonatUser string `db:"donat_user"`
Amount DonatAmount `db:"amount"` Amount DonatAmount `db:"amount"`
Paid bool `db:"paid"` status string `db:"status"`
View bool `db:"view"`
CreatedAt time.Time `db:"created_at"` CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"` UpdatedAt time.Time `db:"updated_at"`
@ -248,6 +248,13 @@ type DonatAndWidget struct {
Display Display Display Display
} }
type CreateDonatBody struct {
TargetID int `json:"targetID"`
Amount int `json:"amount"`
Text string `json:"text"`
DonatUser string `json:"donatUser"`
}
//func (widget *GetWidgetDb) GetMediaUrl(mediaType MediaType) MediaUrl { //func (widget *GetWidgetDb) GetMediaUrl(mediaType MediaType) MediaUrl {
// var mediaUrl MediaUrl // var mediaUrl MediaUrl
// if mediaType == "background_url" { // if mediaType == "background_url" {

View File

@ -34,18 +34,16 @@ CREATE TABLE IF NOT EXISTS files (
CREATE TABLE IF NOT EXISTS donats ( CREATE TABLE IF NOT EXISTS donats (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
streamer_id INTEGER NOT NULL, streamer_id INTEGER NOT NULL,
widget_id INTEGER NOT NULL, widget_id INTEGER REFERENCES widgets(id) NOT NULL,
order_id TEXT NOT NULL, order_id UUID NOT NULL,
target_id INTEGER NOT NULL, target_id INTEGER,
size FLOAT NOT NULL,
status VARCHAR(50) NOT NULL DEFAULT 'pending',
text TEXT NOT NULL, text TEXT NOT NULL,
amount INTEGER NOT NULL, amount INTEGER NOT NULL,
donat_user TEXT NOT NULL, donat_user TEXT NOT NULL,
paid BOOLEAN DEFAULT FALSE,
view BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
); );

View File

@ -155,6 +155,7 @@ SELECT
w.streamer_id, w.streamer_id,
w.template_id, w.template_id,
w.group_id, w.group_id,
w.name,
img.id AS image_id, img.id AS image_id,
img.file_name AS image_file_name, img.file_name AS image_file_name,
img.file_type AS image_type, img.file_type AS image_type,

View File

@ -7,6 +7,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/georgysavva/scany/v2/pgxscan" "github.com/georgysavva/scany/v2/pgxscan"
"github.com/google/uuid"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"log/slog" "log/slog"
"strings" "strings"
@ -24,11 +25,11 @@ type RepoDonat struct {
func (repoDonat *RepoDonat) CreateDonat( func (repoDonat *RepoDonat) CreateDonat(
ctx context.Context, ctx context.Context,
streamerID model.StreamerID, streamerID int,
widgetID model.WidgetID, targetID int,
orderID model.OrderID, widgetID int,
targetID model.TargetID, orderID uuid.UUID,
amount model.DonatAmount, amount int,
text string, text string,
donatUser string, donatUser string,
) error { ) error {
@ -39,6 +40,7 @@ func (repoDonat *RepoDonat) CreateDonat(
"target_id": targetID, "target_id": targetID,
"text": text, "text": text,
"amount": amount, "amount": amount,
"status": "pending",
"donat_user": donatUser, "donat_user": donatUser,
} }
_, err := repoDonat.db.Insert(ctx, sql.CreateDonat, args) _, err := repoDonat.db.Insert(ctx, sql.CreateDonat, args)

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"donat-widget/internal/model" "donat-widget/internal/model"
"donat-widget/internal/model/api" "donat-widget/internal/model/api"
"github.com/google/uuid"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"log/slog" "log/slog"
"mime/multipart" "mime/multipart"
@ -66,42 +67,48 @@ func (donatService *ServiceDonat) CheckToken(
func (donatService *ServiceDonat) CreateDonat( func (donatService *ServiceDonat) CreateDonat(
ctx context.Context, ctx context.Context,
streamerID model.StreamerID, streamerLogin string,
orderID model.OrderID,
targetID model.TargetID,
amount model.DonatAmount,
text string, text string,
donatUser string, donatUser string,
targetID int,
amount int,
) (api.CreatePaymentResponse, error) { ) (api.CreatePaymentResponse, error) {
return api.CreatePaymentResponse{}, nil donatePage, err := donatService.donatRepo.GetDonatPageByLogin(ctx, streamerLogin)
//widgets, err := donatService.widgetRepo.GetAllWidget(ctx, streamerID) if err != nil {
//if err != nil { slog.Error("Failed to get donate page", "error", err.Error())
// slog.Error(err.Error()) return api.CreatePaymentResponse{}, err
// return api.CreatePaymentResponse{}, err }
//}
// widgets, err := donatService.widgetRepo.GetWidgetsByStreamerID(ctx, donatePage.StreamerID)
//var widgetID model.WidgetID if err != nil {
//for _, widget := range widgets { slog.Error(err.Error())
// if widget.MinAmount <= amount { return api.CreatePaymentResponse{}, err
// widgetID = widget.ID }
// }
//} orderID := uuid.New()
//
//err = donatService.donatRepo.CreateDonat( var widgetID int
// ctx, streamerID, widgetID, orderID, targetID, amount, text, donatUser, for _, widget := range widgets {
//) if widget.MinAmount <= amount && widget.MaxAmount <= amount {
//if err != nil { widgetID = widget.ID
// slog.Error(err.Error()) }
// return api.CreatePaymentResponse{}, err }
//}
// err = donatService.donatRepo.CreateDonat(
ctx, donatePage.StreamerID, targetID, widgetID, orderID, amount, text, donatUser,
)
if err != nil {
slog.Error(err.Error())
return api.CreatePaymentResponse{}, err
}
//createPaymentResponse, err := donatService.paymentClient.CreatePayment(streamerID, amount, orderID) //createPaymentResponse, err := donatService.paymentClient.CreatePayment(streamerID, amount, orderID)
//if err != nil { //if err != nil {
// slog.Error(err.Error()) // slog.Error(err.Error())
// return api.CreatePaymentResponse{}, err // return api.CreatePaymentResponse{}, err
//} //}
//
//return createPaymentResponse, nil return api.CreatePaymentResponse{}, err
} }
func (donatService *ServiceDonat) GetDonatByStreamerID( func (donatService *ServiceDonat) GetDonatByStreamerID(

View File

@ -2,10 +2,10 @@ package payment
import ( import (
"bytes" "bytes"
"donat-widget/internal/model"
"donat-widget/internal/model/api" "donat-widget/internal/model/api"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/google/uuid"
"io" "io"
"log/slog" "log/slog"
"net/http" "net/http"
@ -24,9 +24,9 @@ type ClientPayment struct {
} }
func (c *ClientPayment) CreatePayment( func (c *ClientPayment) CreatePayment(
streamerID model.StreamerID, streamerID int,
amount model.DonatAmount, amount int,
orderID model.OrderID, orderID uuid.UUID,
) (api.CreatePaymentResponse, error) { ) (api.CreatePaymentResponse, error) {
requestBody := map[string]any{ requestBody := map[string]any{
"sellerID": streamerID, "sellerID": streamerID,

View File

@ -42,8 +42,7 @@ CREATE TABLE IF NOT EXISTS donats (
text TEXT NOT NULL, text TEXT NOT NULL,
amount INTEGER NOT NULL, amount INTEGER NOT NULL,
donat_user TEXT NOT NULL, donat_user TEXT NOT NULL,
paid BOOLEAN DEFAULT FALSE, status VARCHAR(50) NOT NULL DEFAULT 'pending',
view BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
); );