add router for get statistic by date

This commit is contained in:
harold 2025-03-09 19:28:16 +05:00
parent f5e143c044
commit 476e6ff59c
10 changed files with 387 additions and 0 deletions

View File

@ -455,3 +455,39 @@ func UpdateModerationSettings(donatService model.DonatService) echo.HandlerFunc
return request.JSON(http.StatusOK, "Success update") return request.JSON(http.StatusOK, "Success update")
} }
} }
// GetDonationsStats godoc
// @Summary Get donations statistics
// @Description Get donations statistics for a given period
// @Tags Donate
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param period query string true "Period for statistics" Enums(24h, 7d, 1m, 1y)
// @Success 200 {array} model.DonationStatResponse "Donations statistics"
// @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/period-stat [get]
func GetDonationsStats(donatService model.DonatService) echo.HandlerFunc {
return func(request echo.Context) error {
authData, err := donatService.CheckToken(request)
if err != nil {
slog.Error("Unauthorized")
return echo.NewHTTPError(http.StatusUnauthorized, err.Error())
}
ctx := context.Background()
period := request.QueryParam("period")
if period == "" {
return echo.NewHTTPError(http.StatusBadRequest, "period is required")
}
stats, err := donatService.GetDonationsStats(ctx, authData.AccountID, period)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
}
return request.JSON(http.StatusOK, stats)
}
}

View File

@ -88,6 +88,8 @@ func IncludeDonatHandlers(
server.POST(PREFIX+"/donat/view/:donatID", MarkDonatView(donatService)) server.POST(PREFIX+"/donat/view/:donatID", MarkDonatView(donatService))
server.POST(PREFIX+"/donat/paid", MarkDonatPaid(donatService)) server.POST(PREFIX+"/donat/paid", MarkDonatPaid(donatService))
server.GET(PREFIX+"/donat/period-stat", GetDonationsStats(donatService))
} }
func IncludeWidgetHandlers( func IncludeWidgetHandlers(

View File

@ -93,6 +93,70 @@ const docTemplate = `{
} }
} }
}, },
"/donat/period-stat": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Get donations statistics for a given period",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Donate"
],
"summary": "Get donations statistics",
"parameters": [
{
"enum": [
"24h",
"7d",
"1m",
"1y"
],
"type": "string",
"description": "Period for statistics",
"name": "period",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "Donations statistics",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/donat-widget_internal_model.DonationStatResponse"
}
}
},
"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/{streamer-login}": { "/donat/{streamer-login}": {
"post": { "post": {
"description": "Create donat", "description": "Create donat",
@ -979,6 +1043,20 @@ const docTemplate = `{
} }
} }
}, },
"donat-widget_internal_model.DonationStatResponse": {
"type": "object",
"properties": {
"amount_collected": {
"type": "integer"
},
"date": {
"type": "string"
},
"donations_count": {
"type": "integer"
}
}
},
"donat-widget_internal_model.FilterSettingResponse": { "donat-widget_internal_model.FilterSettingResponse": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -86,6 +86,70 @@
} }
} }
}, },
"/donat/period-stat": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Get donations statistics for a given period",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Donate"
],
"summary": "Get donations statistics",
"parameters": [
{
"enum": [
"24h",
"7d",
"1m",
"1y"
],
"type": "string",
"description": "Period for statistics",
"name": "period",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "Donations statistics",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/donat-widget_internal_model.DonationStatResponse"
}
}
},
"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/{streamer-login}": { "/donat/{streamer-login}": {
"post": { "post": {
"description": "Create donat", "description": "Create donat",
@ -972,6 +1036,20 @@
} }
} }
}, },
"donat-widget_internal_model.DonationStatResponse": {
"type": "object",
"properties": {
"amount_collected": {
"type": "integer"
},
"date": {
"type": "string"
},
"donations_count": {
"type": "integer"
}
}
},
"donat-widget_internal_model.FilterSettingResponse": { "donat-widget_internal_model.FilterSettingResponse": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -66,6 +66,15 @@ definitions:
streamer_id: streamer_id:
type: integer type: integer
type: object type: object
donat-widget_internal_model.DonationStatResponse:
properties:
amount_collected:
type: integer
date:
type: string
donations_count:
type: integer
type: object
donat-widget_internal_model.FilterSettingResponse: donat-widget_internal_model.FilterSettingResponse:
properties: properties:
enable_links: enable_links:
@ -424,6 +433,48 @@ paths:
summary: Create donat summary: Create donat
tags: tags:
- Donate - Donate
/donat/period-stat:
get:
consumes:
- application/json
description: Get donations statistics for a given period
parameters:
- description: Period for statistics
enum:
- 24h
- 7d
- 1m
- 1y
in: query
name: period
required: true
type: string
produces:
- application/json
responses:
"200":
description: Donations statistics
schema:
items:
$ref: '#/definitions/donat-widget_internal_model.DonationStatResponse'
type: array
"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 donations statistics
tags:
- Donate
/files: /files:
post: post:
consumes: consumes:

View File

@ -98,6 +98,8 @@ type DonatService interface {
GetModerationSettings(ctx context.Context, streamerID int) (ModerationResponse, error) GetModerationSettings(ctx context.Context, streamerID int) (ModerationResponse, error)
UpdateModerationSettings(ctx context.Context, streamerID int, updateModel UpdateModeration) error UpdateModerationSettings(ctx context.Context, streamerID int, updateModel UpdateModeration) error
GetDonationsStats(ctx context.Context, streamerID int, period string) ([]DonationStatResponse, error)
} }
type DonatRepo interface { type DonatRepo interface {
@ -147,6 +149,8 @@ type DonatRepo interface {
GetModeration(ctx context.Context, streamerID int) (ModerationResponse, error) GetModeration(ctx context.Context, streamerID int) (ModerationResponse, error)
UpdateModeration(ctx context.Context, streamerID int, enable *bool, duration *int) error UpdateModeration(ctx context.Context, streamerID int, enable *bool, duration *int) error
GetDonationsStats(ctx context.Context, streamerID int, period string) ([]DonationStat, error)
} }
type TargetService interface { type TargetService interface {

View File

@ -255,6 +255,18 @@ type CreateDonatBody struct {
DonatUser string `json:"donatUser"` DonatUser string `json:"donatUser"`
} }
type DonationStat struct {
Date time.Time `db:"date"`
AmountCollected int `db:"amount_collected"`
DonationsCount int `db:"donations_count"`
}
type DonationStatResponse struct {
Date time.Time `json:"date"`
AmountCollected int `json:"amount_collected"`
DonationsCount int `json:"donations_count"`
}
//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

@ -313,3 +313,67 @@ WHERE streamer_id = @streamer_id;
` `
var GetModeration = ` var GetModeration = `
SELECT enable, duration FROM moderation WHERE streamer_id = @streamer_id;` SELECT enable, duration FROM moderation WHERE streamer_id = @streamer_id;`
const GetDonationsLast24Hours = `
SELECT
DATE_TRUNC('hour', created_at) AS date, -- Группировка по часам
SUM(amount) AS amount_collected,
COUNT(*) AS donations_count
FROM
public.donats
WHERE
streamer_id = @streamer_id
AND created_at >= NOW() - INTERVAL '24 hours'
GROUP BY
DATE_TRUNC('hour', created_at) -- Группировка по часам
ORDER BY
date;
`
const GetDonationsLast7Days = `
SELECT
DATE(created_at) AS date, -- Группировка по дням
SUM(amount) AS amount_collected,
COUNT(*) AS donations_count
FROM
public.donats
WHERE
streamer_id = @streamer_id
AND created_at >= NOW() - INTERVAL '7 days'
GROUP BY
DATE(created_at) -- Группировка по дням
ORDER BY
date;
`
const GetDonationsLastMonth = `
SELECT
DATE(created_at) AS date, -- Группировка по дням
SUM(amount) AS amount_collected,
COUNT(*) AS donations_count
FROM
public.donats
WHERE
streamer_id = @streamer_id
AND created_at >= NOW() - INTERVAL '1 month'
GROUP BY
DATE(created_at) -- Группировка по дням
ORDER BY
date;
`
const GetDonationsLastYear = `
SELECT
DATE_TRUNC('month', created_at) AS date, -- Группировка по месяцам
SUM(amount) AS amount_collected,
COUNT(*) AS donations_count
FROM
public.donats
WHERE
streamer_id = @streamer_id
AND created_at >= NOW() - INTERVAL '1 year'
GROUP BY
DATE_TRUNC('month', created_at) -- Группировка по месяцам
ORDER BY
date;
`

View File

@ -604,3 +604,42 @@ func (repoDonat *RepoDonat) UpdateModeration(
} }
return nil return nil
} }
func (repoDonat *RepoDonat) GetDonationsStats(
ctx context.Context,
streamerID int,
period string, // "24h", "7d", "1m", "1y"
) ([]model.DonationStat, error) {
var query string
switch period {
case "24h":
query = sql.GetDonationsLast24Hours
case "7d":
query = sql.GetDonationsLast7Days
case "1m":
query = sql.GetDonationsLastMonth
case "1y":
query = sql.GetDonationsLastYear
default:
return nil, errors.New("invalid period")
}
args := pgx.NamedArgs{
"streamer_id": streamerID,
}
rows, err := repoDonat.db.Select(ctx, query, args)
if err != nil {
slog.Error(err.Error())
return nil, err
}
var stats []model.DonationStat
err = pgxscan.ScanAll(&stats, rows)
if err != nil {
slog.Error(err.Error())
return nil, err
}
return stats, nil
}

View File

@ -455,3 +455,26 @@ func (donatService *ServiceDonat) UpdateModerationSettings(
} }
return nil return nil
} }
func (donatService *ServiceDonat) GetDonationsStats(
ctx context.Context,
streamerID int,
period string,
) ([]model.DonationStatResponse, error) {
stats, err := donatService.donatRepo.GetDonationsStats(ctx, streamerID, period)
if err != nil {
slog.Error(err.Error())
return nil, err
}
var response []model.DonationStatResponse
for _, stat := range stats {
response = append(response, model.DonationStatResponse{
Date: stat.Date,
AmountCollected: stat.AmountCollected,
DonationsCount: stat.DonationsCount,
})
}
return response, nil
}