add router for download files

This commit is contained in:
harold 2025-03-06 12:13:09 +05:00
parent 8e7336b2ca
commit 70269a3bb4
15 changed files with 459 additions and 80 deletions

View File

@ -69,10 +69,9 @@ func (ls *LocalStorage) Upload(
func (ls *LocalStorage) Download(
filename string,
extension string,
filePath string,
folder string,
) ([]byte, error) {
f, err := os.Open(filePath + "/" + filename + "." + extension)
f, err := os.Open(ls.basePath + "/" + folder + "/" + filename)
if err != nil {
return nil, err
}

View File

@ -17,7 +17,7 @@ import (
// @Produce json
// @Security BearerAuth
// @Param new_file formData file false "New file"
// @Success 200 {string} string "Widget has been uploaded successfully!"
// @Success 200 {string} string "GetWidgetDb has been uploaded successfully!"
// @Failure 400 {object} echo.HTTPError "Bad request"
// @Failure 401 {object} echo.HTTPError "Unauthorized or expired token"
// @Failure 422 {object} echo.HTTPError "Validation error"
@ -54,3 +54,30 @@ func AddNewFile(fileService model.FileService) echo.HandlerFunc {
return request.JSON(http.StatusOK, "")
}
}
// GetFile godoc
// @Summary Get a file
// @Description Retrieve a file by its ID
// @Tags Files
// @Accept json
// @Produce octet-stream
// @Param file_id path int true "File ID"
// @Success 200 {file} binary "File content"
// @Failure 400 {object} echo.HTTPError "Bad request"
// @Failure 401 {object} echo.HTTPError "Unauthorized or expired token"
// @Failure 404 {object} echo.HTTPError "File not found"
// @Router /files/{file_id} [get]
func GetFile(fileService model.FileService) echo.HandlerFunc {
return func(request echo.Context) error {
ctx := context.Background()
fileID := request.Param("file_id")
file, fileType, err := fileService.GetByID(ctx, fileID)
if err != nil {
slog.Error(err.Error())
return echo.NewHTTPError(http.StatusNotFound, "File not found")
}
return request.Blob(http.StatusOK, fileType, file)
}
}

View File

@ -12,12 +12,12 @@ import (
// CreateWidget godoc
// @Summary Create new widget
// @Description Create new widget
// @Tags Widget
// @Tags GetWidgetDb
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body model.CreateWidgetBody true "Create widget"
// @Success 200 {string} string "Widget has been created successfully!"
// @Success 200 {string} string "GetWidgetDb has been created successfully!"
// @Failure 400 {object} echo.HTTPError "Bad request"
// @Failure 401 {object} echo.HTTPError "Unauthorized or expired token"
// @Failure 422 {object} echo.HTTPError "Validation error"
@ -59,6 +59,44 @@ func CreateWidget(widgetService model.WidgetService) echo.HandlerFunc {
}
}
// GetStreamersWidgets godoc
// @Summary Get all streamer's widgets
// @Description Get all streamer's widgets
// @Tags GetWidgetDb
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {string} string "GetWidgetDb has been created 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 /widgets [get]
func GetStreamersWidgets(widgetService model.WidgetService) echo.HandlerFunc {
return func(request echo.Context) error {
ctx := context.Background()
var body model.CreateWidgetBody
err := validator.ParseAndValidate(&body, request)
authData, err := widgetService.CheckToken(request)
if err != nil {
slog.Error(err.Error())
return echo.NewHTTPError(http.StatusUnauthorized, err.Error())
}
widgets, err := widgetService.GetWidgetsByStreamer(
ctx,
authData.AccountID,
)
if err != nil {
slog.Error(err.Error())
return request.JSON(http.StatusInternalServerError, err.Error())
}
return request.JSON(http.StatusOK, widgets)
}
}
//func GetWidgetHTML(widgetService model.WidgetService) echo.HandlerFunc {
// return func(request echo.Context) error {
// ctx := context.Background()

View File

@ -85,6 +85,7 @@ func IncludeWidgetHandlers(
widgetService model.WidgetService,
) {
server.POST(PREFIX+"/widgets", widget.CreateWidget(widgetService))
server.GET(PREFIX+"/widgets", widget.GetStreamersWidgets(widgetService))
//server.GET(PREFIX+"/html/:streamerID", model.GetWidgetHTML(widgetService))
//server.GET(PREFIX+"/info/:widgetID", model.GetWidgetInfo(widgetService))
@ -101,4 +102,5 @@ func IncludeFileHandlers(
fileService model.FileService,
) {
server.POST(PREFIX+"/files", files.AddNewFile(fileService))
server.GET(PREFIX+"/files/:file_id", files.GetFile(fileService))
}

View File

@ -112,7 +112,7 @@ const docTemplate = `{
],
"responses": {
"200": {
"description": "Widget has been uploaded successfully!",
"description": "GetWidgetDb has been uploaded successfully!",
"schema": {
"type": "string"
}
@ -138,6 +138,56 @@ const docTemplate = `{
}
}
},
"/files/{file_id}": {
"get": {
"description": "Retrieve a file by its ID",
"consumes": [
"application/json"
],
"produces": [
"application/octet-stream"
],
"tags": [
"Files"
],
"summary": "Get a file",
"parameters": [
{
"type": "string",
"description": "File ID",
"name": "file_id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "File content",
"schema": {
"type": "file"
}
},
"400": {
"description": "Bad request",
"schema": {
"$ref": "#/definitions/echo.HTTPError"
}
},
"401": {
"description": "Unauthorized or expired token",
"schema": {
"$ref": "#/definitions/echo.HTTPError"
}
},
"404": {
"description": "File not found",
"schema": {
"$ref": "#/definitions/echo.HTTPError"
}
}
}
}
},
"/filters-settings": {
"get": {
"description": "Get donat filters settings",
@ -509,6 +559,50 @@ const docTemplate = `{
}
},
"/widgets": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Get all streamer's widgets",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"GetWidgetDb"
],
"summary": "Get all streamer's widgets",
"responses": {
"200": {
"description": "GetWidgetDb has been created 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"
}
}
}
},
"post": {
"security": [
{
@ -523,7 +617,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"Widget"
"GetWidgetDb"
],
"summary": "Create new widget",
"parameters": [
@ -539,7 +633,7 @@ const docTemplate = `{
],
"responses": {
"200": {
"description": "Widget has been created successfully!",
"description": "GetWidgetDb has been created successfully!",
"schema": {
"type": "string"
}
@ -603,7 +697,7 @@ const docTemplate = `{
},
"name": {
"type": "string",
"example": "My Widget"
"example": "My GetWidgetDb"
},
"template_id": {
"type": "integer",

View File

@ -105,7 +105,7 @@
],
"responses": {
"200": {
"description": "Widget has been uploaded successfully!",
"description": "GetWidgetDb has been uploaded successfully!",
"schema": {
"type": "string"
}
@ -131,6 +131,56 @@
}
}
},
"/files/{file_id}": {
"get": {
"description": "Retrieve a file by its ID",
"consumes": [
"application/json"
],
"produces": [
"application/octet-stream"
],
"tags": [
"Files"
],
"summary": "Get a file",
"parameters": [
{
"type": "string",
"description": "File ID",
"name": "file_id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "File content",
"schema": {
"type": "file"
}
},
"400": {
"description": "Bad request",
"schema": {
"$ref": "#/definitions/echo.HTTPError"
}
},
"401": {
"description": "Unauthorized or expired token",
"schema": {
"$ref": "#/definitions/echo.HTTPError"
}
},
"404": {
"description": "File not found",
"schema": {
"$ref": "#/definitions/echo.HTTPError"
}
}
}
}
},
"/filters-settings": {
"get": {
"description": "Get donat filters settings",
@ -502,6 +552,50 @@
}
},
"/widgets": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Get all streamer's widgets",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"GetWidgetDb"
],
"summary": "Get all streamer's widgets",
"responses": {
"200": {
"description": "GetWidgetDb has been created 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"
}
}
}
},
"post": {
"security": [
{
@ -516,7 +610,7 @@
"application/json"
],
"tags": [
"Widget"
"GetWidgetDb"
],
"summary": "Create new widget",
"parameters": [
@ -532,7 +626,7 @@
],
"responses": {
"200": {
"description": "Widget has been created successfully!",
"description": "GetWidgetDb has been created successfully!",
"schema": {
"type": "string"
}
@ -596,7 +690,7 @@
},
"name": {
"type": "string",
"example": "My Widget"
"example": "My GetWidgetDb"
},
"template_id": {
"type": "integer",

View File

@ -20,7 +20,7 @@ definitions:
example: 10
type: integer
name:
example: My Widget
example: My GetWidgetDb
type: string
template_id:
example: 1
@ -201,7 +201,7 @@ paths:
- application/json
responses:
"200":
description: Widget has been uploaded successfully!
description: GetWidgetDb has been uploaded successfully!
schema:
type: string
"400":
@ -221,6 +221,39 @@ paths:
summary: Add new File
tags:
- Files
/files/{file_id}:
get:
consumes:
- application/json
description: Retrieve a file by its ID
parameters:
- description: File ID
in: path
name: file_id
required: true
type: string
produces:
- application/octet-stream
responses:
"200":
description: File content
schema:
type: file
"400":
description: Bad request
schema:
$ref: '#/definitions/echo.HTTPError'
"401":
description: Unauthorized or expired token
schema:
$ref: '#/definitions/echo.HTTPError'
"404":
description: File not found
schema:
$ref: '#/definitions/echo.HTTPError'
summary: Get a file
tags:
- Files
/filters-settings:
get:
consumes:
@ -465,6 +498,34 @@ paths:
tags:
- Donate
/widgets:
get:
consumes:
- application/json
description: Get all streamer's widgets
produces:
- application/json
responses:
"200":
description: GetWidgetDb has been created 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: Get all streamer's widgets
tags:
- GetWidgetDb
post:
consumes:
- application/json
@ -480,7 +541,7 @@ paths:
- application/json
responses:
"200":
description: Widget has been created successfully!
description: GetWidgetDb has been created successfully!
schema:
type: string
"400":
@ -499,7 +560,7 @@ paths:
- BearerAuth: []
summary: Create new widget
tags:
- Widget
- GetWidgetDb
securityDefinitions:
BearerAuth:
in: header

View File

@ -24,8 +24,9 @@ type WidgetService interface {
audio string,
name string,
) (WidgetID, error)
GetWidgetsByStreamer(ctx context.Context, streamerID int) ([]*GetWidgetDb, error)
//GetWidgetByID(ctx context.Context, widgetID WidgetID) ([]*Widget, error)
//GetWidgetByID(ctx context.Context, widgetID WidgetID) ([]*GetWidgetDb, error)
//GetWidgetHTML(ctx context.Context, streamerID StreamerID) (WidgetHTML, error)
//GetMediaFile(ctx context.Context, widgetID WidgetID, mediaType MediaType) (DownloadFile, error)
//
@ -46,9 +47,10 @@ type WidgetRepo interface {
) (WidgetID, error)
CheckWidgetName(ctx context.Context, streamerID int, name string) (bool, error)
//GetWidgetByStreamerID(ctx context.Context, streamerID StreamerID) ([]*Widget, error)
//GetWidgetByID(ctx context.Context, widgetID WidgetID) ([]*Widget, error)
//GetAllWidget(ctx context.Context, streamerID StreamerID) ([]*Widget, error)
GetWidgetsByStreamerID(ctx context.Context, streamerID int) ([]*GetWidgetDb, error)
//GetWidgetByID(ctx context.Context, widgetID WidgetID) ([]*GetWidgetDb, error)
//GetAllWidget(ctx context.Context, streamerID StreamerID) ([]*GetWidgetDb, error)
//GetMediaFile(fileID FileID) (DownloadFile, error)
//GetMediaUrl(ctx context.Context, widgetID WidgetID, mediaType MediaType) (MediaUrl, error)
//
@ -119,7 +121,7 @@ type Error interface {
type Storage interface {
Upload(file *multipart.FileHeader, streamerID int) (string, error)
Download(filename, extension, filePath string) ([]byte, error)
Download(filename, folder string) ([]byte, error)
Delete(filename, extension, filePath string) error
}
@ -149,6 +151,7 @@ type FileRepo interface {
file multipart.FileHeader,
extension, fileType string,
) (string, error)
GetByID(ctx context.Context, fileID string) ([]byte, string, error)
}
type FileService interface {
@ -159,4 +162,5 @@ type FileService interface {
file multipart.FileHeader,
streamerID int,
) (string, error)
GetByID(ctx context.Context, fileID string) ([]byte, string, error)
}

View File

@ -4,22 +4,23 @@ import (
"time"
)
type File struct {
ID string `json:"id"`
FileName string `json:"file_name"`
Extension string `json:"extension"`
FileType string `json:"file_type"`
}
type GetWidgetDb struct {
ID int `db:"id"`
StreamerID int `db:"streamer_id"`
TemplateID int `db:"template_id"`
Duration int `db:"duration"`
MinAmount int `db:"min_amount"`
MaxAmount int `db:"max_amount"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
type Widget struct {
ID int `db:"id"`
StreamerID int `db:"streamer_id"`
TemplateID int `db:"template_id"`
Duration int `db:"duration"`
MinAmount int `db:"min_amount"`
CreatedAt string `db:"created_at"`
UpdatedAt string `db:"updated_at"`
Files []File `db:"files"`
// Поля для изображения
ImageFileName string `db:"image_file_name"`
ImageType string `db:"image_type"`
// Поля для аудио
AudioFileName string `db:"audio_file_name"`
AudioType string `db:"audio_type"`
}
type Donat struct {
@ -172,7 +173,7 @@ type CreateWidgetResponse struct {
type CreateWidgetBody struct {
TemplateID int `json:"template_id" validate:"required" example:"1"`
Duration int `json:"duration" validate:"required" example:"30"`
Name string `json:"name" validate:"required" example:"My Widget"`
Name string `json:"name" validate:"required" example:"My GetWidgetDb"`
Image string `json:"image" validate:"required" format:"uuid" example:"550e8400-e29b-41d4-a716-446655440000"`
Audio string `json:"audio" validate:"required" format:"uuid" example:"550e8400-e29b-41d4-a716-446655440001"`
MinAmount int `json:"min_amount" validate:"required" example:"10"`
@ -184,7 +185,7 @@ type DonatAndWidget struct {
Display Display
}
//func (widget *Widget) GetMediaUrl(mediaType MediaType) MediaUrl {
//func (widget *GetWidgetDb) GetMediaUrl(mediaType MediaType) MediaUrl {
// var mediaUrl MediaUrl
// if mediaType == "background_url" {
// mediaUrl = widget.Background
@ -196,7 +197,7 @@ type DonatAndWidget struct {
// return mediaUrl
//}
//
//func (widget *Widget) NormalizeUrl() {
//func (widget *GetWidgetDb) NormalizeUrl() {
// selfDomain := "http://localhost:8002/api/widget/media"
// strWidgetID := strconv.Itoa(int(widget.ID))
// if !strings.Contains(string(widget.ImageUrl), "http") && widget.ImageUrl != "" {

View File

@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS widgets (
CREATE TABLE IF NOT EXISTS files (
id UUID NOT NULL PRIMARY KEY DEFAULT uuid_generate_v4(),
file_type VARCHAR(15) NOT NULL,
file_name VARCHAR(50) NOT NULL,
extension VARCHAR(10) NOT NULL,
streamer_id INTEGER NOT NULL,
created_at TIMESTAMP DEFAULT now()

View File

@ -91,28 +91,23 @@ var GetDonationPageByLogin = `
SELECT * FROM donate_pages WHERE streamer_login = (@streamer_login);
`
var GetWidget = `
var GetWidgetsByStreamerID = `
SELECT
w.id,
w.streamer_id,
w.template_id,
bg.file_name AS background_file_name,
bg.extension AS background_extension,
bg.type AS background_type,
img.file_name AS image_file_name,
img.extension AS image_extension,
img.type AS image_type,
img.file_type AS image_type,
audio.file_name AS audio_file_name,
audio.extension AS audio_extension,
audio.type AS audio_type,
audio.file_type AS audio_type,
w.duration,
w.min_amount,
w.created_at,
w.updated_at
FROM widgets w
LEFT JOIN files bg ON w.background = bg.id
LEFT JOIN files img ON w.image = img.id
LEFT JOIN files audio ON w.audio = audio.id
WHERE w.streamer_id = (@streamer_id);
`
var AddNewFile = `
@ -126,3 +121,5 @@ var GetWidgetByName = `SELECT id FROM widgets WHERE (
streamer_id = @streamer_id AND
name = @name);
`
var FileById = `SELECT file_name, streamer_id, file_type FROM files WHERE id = (@id);`

View File

@ -8,6 +8,7 @@ import (
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"mime/multipart"
"strconv"
)
func New(
@ -56,3 +57,33 @@ func (fileRepo *RepoFile) AddNew(
return fileID, nil
}
func (fileRepo *RepoFile) GetByID(
ctx context.Context,
fileID string,
) ([]byte, string, error) {
args := pgx.NamedArgs{
"id": fileID,
}
row, err := fileRepo.db.SelectOne(ctx, sql.FileById, args)
if err != nil {
return nil, "", fmt.Errorf("error retrieving file info: %v", err)
}
if row == nil {
return nil, "", fmt.Errorf("file %s not found", fileID)
}
var fileName string
var streamerID int
var fileType string
err = row.Scan(&fileName, &streamerID, &fileType)
fileContent, err := fileRepo.storage.Download(fileName, strconv.Itoa(streamerID))
if err != nil {
return nil, "", fmt.Errorf("error downloading file: %v", err)
}
return fileContent, fileType, nil
}

View File

@ -4,6 +4,7 @@ import (
"context"
"donat-widget/internal/model"
"donat-widget/internal/model/sql"
"github.com/georgysavva/scany/v2/pgxscan"
"github.com/jackc/pgx/v5"
"log/slog"
)
@ -75,32 +76,32 @@ func (widgetRepo *RepoWidget) CheckWidgetName(
return true, nil
}
//
//func (widgetRepo *RepoWidget) GetWidgetByStreamerID(
// ctx context.Context,
// streamerID model.StreamerID,
//) ([]*model.Widget, error) {
// args := pgx.NamedArgs{"streamer_id": streamerID}
// rows, err := widgetRepo.db.Select(ctx, sql.GetWidgetByStreamerID, args)
// if err != nil {
// slog.Error(err.Error())
// return nil, err
// }
//
// var widgets []*model.Widget
// err = pgxscan.ScanAll(&widgets, rows)
// if err != nil {
// slog.Error(err.Error())
// return nil, err
// }
//
// return widgets, nil
//}
func (widgetRepo *RepoWidget) GetWidgetsByStreamerID(
ctx context.Context,
streamerID int,
) ([]*model.GetWidgetDb, error) {
args := pgx.NamedArgs{"streamer_id": streamerID}
rows, err := widgetRepo.db.Select(ctx, sql.GetWidgetsByStreamerID, args)
if err != nil {
slog.Error(err.Error())
return nil, err
}
var widgets []*model.GetWidgetDb
err = pgxscan.ScanAll(&widgets, rows)
if err != nil {
slog.Error(err.Error())
return nil, err
}
return widgets, nil
}
//
//func (widgetRepo *RepoWidget) GetWidgetByID(
// ctx context.Context,
// widgetID model.WidgetID,
//) ([]*model.Widget, error) {
//) ([]*model.GetWidgetDb, error) {
// args := pgx.NamedArgs{"id": widgetID}
// rows, err := widgetRepo.db.Select(ctx, sql.GetWidgetByID, args)
// if err != nil {
@ -108,7 +109,7 @@ func (widgetRepo *RepoWidget) CheckWidgetName(
// return nil, err
// }
//
// var widgets []*model.Widget
// var widgets []*model.GetWidgetDb
// err = pgxscan.ScanAll(&widgets, rows)
// if err != nil {
// slog.Error(err.Error())
@ -121,7 +122,7 @@ func (widgetRepo *RepoWidget) CheckWidgetName(
//func (widgetRepo *RepoWidget) GetAllWidget(
// ctx context.Context,
// streamerID model.StreamerID,
//) ([]*model.Widget, error) {
//) ([]*model.GetWidgetDb, error) {
// args := pgx.NamedArgs{
// "streamer_id": streamerID,
// }
@ -131,7 +132,7 @@ func (widgetRepo *RepoWidget) CheckWidgetName(
// return nil, err
// }
//
// var widgets []*model.Widget
// var widgets []*model.GetWidgetDb
// err = pgxscan.ScanAll(&widgets, rows)
// if err != nil {
// slog.Error(err.Error())
@ -233,7 +234,7 @@ func (widgetRepo *RepoWidget) CheckWidgetName(
// return "", err
// }
//
// var widgets []*model.Widget
// var widgets []*model.GetWidgetDb
// err = pgxscan.ScanAll(&widgets, rows)
// if err != nil {
// slog.Error(err.Error())
@ -241,7 +242,7 @@ func (widgetRepo *RepoWidget) CheckWidgetName(
// }
//
// if len(widgets) == 0 {
// slog.Error("Widget does not exist")
// slog.Error("GetWidgetDb does not exist")
// return "", errors.New("widget does not exist")
// }
//

View File

@ -55,6 +55,21 @@ func (fileService *ServiceFile) AddNewFile(
return fileID, nil
}
func (fileService *ServiceFile) GetByID(
ctx context.Context,
fileID string,
) ([]byte, string, error) {
fileBytes, fileType, err := fileService.fileRepo.GetByID(
ctx,
fileID,
)
if err != nil {
return nil, "", err
}
return fileBytes, fileType, nil
}
func (fileService *ServiceFile) CheckToken(
request echo.Context,
) (api.CheckTokenResponse, error) {

View File

@ -45,7 +45,7 @@ func (widgetService *ServiceWidget) CreateWidget(
}
fmt.Println(exists)
if exists == true {
slog.Error("Widget with name %s already exists", name)
slog.Error("GetWidgetDb with name %s already exists", name)
return 0, fmt.Errorf("widget with name %s already exists", name)
}
@ -67,13 +67,27 @@ func (widgetService *ServiceWidget) CreateWidget(
return widgetID, nil
}
func (widgetService *ServiceWidget) GetWidgetsByStreamer(
ctx context.Context,
streamerID int,
) ([]*model.GetWidgetDb, error) {
widget, err := widgetService.widgetRepo.GetWidgetsByStreamerID(ctx, streamerID)
if err != nil {
slog.Error(err.Error())
return nil, err
}
return widget, nil
}
//
//func (widgetService *ServiceWidget) GetWidgetHTML(
// ctx context.Context,
// streamerID model.StreamerID,
//) (model.WidgetHTML, error) {
//
// widgets, err := widgetService.widgetRepo.GetWidgetByStreamerID(ctx, streamerID)
// widgets, err := widgetService.widgetRepo.GetWidgetsByStreamerID(ctx, streamerID)
// if err != nil {
// slog.Error(err.Error())
// return "", err
@ -97,7 +111,7 @@ func (widgetService *ServiceWidget) CreateWidget(
//func (widgetService *ServiceWidget) GetWidgetByID(
// ctx context.Context,
// widgetID model.WidgetID,
//) ([]*model.Widget, error) {
//) ([]*model.GetWidgetDb, error) {
//
// widget, err := widgetService.widgetRepo.GetWidgetByID(ctx, widgetID)
// if err != nil {