From 31a2d2ec58027d9c5355688b422d693f18d7bd5d Mon Sep 17 00:00:00 2001 From: harold Date: Sun, 9 Mar 2025 19:40:47 +0500 Subject: [PATCH] add stats fixes --- internal/api/http/handlers/donat/donat.go | 2 +- internal/docs/docs.go | 29 ++++++++++++++- internal/docs/swagger.json | 29 ++++++++++++++- internal/docs/swagger.yaml | 20 ++++++++++- internal/model/interfaces.go | 3 +- internal/model/models.go | 10 ++++++ internal/model/sql/query.go | 44 +++++++++++++++++++++++ internal/repository/donat/donat.go | 38 ++++++++++++++++++++ internal/service/donat/donat.go | 22 +++++++++--- 9 files changed, 188 insertions(+), 9 deletions(-) diff --git a/internal/api/http/handlers/donat/donat.go b/internal/api/http/handlers/donat/donat.go index 89323e1..7a8c426 100644 --- a/internal/api/http/handlers/donat/donat.go +++ b/internal/api/http/handlers/donat/donat.go @@ -464,7 +464,7 @@ func UpdateModerationSettings(donatService model.DonatService) echo.HandlerFunc // @Produce json // @Security BearerAuth // @Param period query string true "Period for statistics" Enums(24h, 7d, 1m, 1y) -// @Success 200 {array} model.DonationStatResponse "Donations statistics" +// @Success 200 {array} model.DonationSummaryResponse "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" diff --git a/internal/docs/docs.go b/internal/docs/docs.go index 9b281d9..4563b8c 100644 --- a/internal/docs/docs.go +++ b/internal/docs/docs.go @@ -132,7 +132,7 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/donat-widget_internal_model.DonationStatResponse" + "$ref": "#/definitions/donat-widget_internal_model.DonationSummaryResponse" } } }, @@ -1057,6 +1057,33 @@ const docTemplate = `{ } } }, + "donat-widget_internal_model.DonationSummary": { + "type": "object", + "properties": { + "donations_count": { + "description": "Общее количество донатов", + "type": "integer" + }, + "total_amount": { + "description": "Общая сумма донатов", + "type": "integer" + } + } + }, + "donat-widget_internal_model.DonationSummaryResponse": { + "type": "object", + "properties": { + "donation_sum": { + "$ref": "#/definitions/donat-widget_internal_model.DonationSummary" + }, + "donations": { + "type": "array", + "items": { + "$ref": "#/definitions/donat-widget_internal_model.DonationStatResponse" + } + } + } + }, "donat-widget_internal_model.FilterSettingResponse": { "type": "object", "properties": { diff --git a/internal/docs/swagger.json b/internal/docs/swagger.json index 31cec24..644c419 100644 --- a/internal/docs/swagger.json +++ b/internal/docs/swagger.json @@ -125,7 +125,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/donat-widget_internal_model.DonationStatResponse" + "$ref": "#/definitions/donat-widget_internal_model.DonationSummaryResponse" } } }, @@ -1050,6 +1050,33 @@ } } }, + "donat-widget_internal_model.DonationSummary": { + "type": "object", + "properties": { + "donations_count": { + "description": "Общее количество донатов", + "type": "integer" + }, + "total_amount": { + "description": "Общая сумма донатов", + "type": "integer" + } + } + }, + "donat-widget_internal_model.DonationSummaryResponse": { + "type": "object", + "properties": { + "donation_sum": { + "$ref": "#/definitions/donat-widget_internal_model.DonationSummary" + }, + "donations": { + "type": "array", + "items": { + "$ref": "#/definitions/donat-widget_internal_model.DonationStatResponse" + } + } + } + }, "donat-widget_internal_model.FilterSettingResponse": { "type": "object", "properties": { diff --git a/internal/docs/swagger.yaml b/internal/docs/swagger.yaml index e7949c0..6bc7bac 100644 --- a/internal/docs/swagger.yaml +++ b/internal/docs/swagger.yaml @@ -75,6 +75,24 @@ definitions: donations_count: type: integer type: object + donat-widget_internal_model.DonationSummary: + properties: + donations_count: + description: Общее количество донатов + type: integer + total_amount: + description: Общая сумма донатов + type: integer + type: object + donat-widget_internal_model.DonationSummaryResponse: + properties: + donation_sum: + $ref: '#/definitions/donat-widget_internal_model.DonationSummary' + donations: + items: + $ref: '#/definitions/donat-widget_internal_model.DonationStatResponse' + type: array + type: object donat-widget_internal_model.FilterSettingResponse: properties: enable_links: @@ -456,7 +474,7 @@ paths: description: Donations statistics schema: items: - $ref: '#/definitions/donat-widget_internal_model.DonationStatResponse' + $ref: '#/definitions/donat-widget_internal_model.DonationSummaryResponse' type: array "400": description: Bad request diff --git a/internal/model/interfaces.go b/internal/model/interfaces.go index c567571..7d7089c 100644 --- a/internal/model/interfaces.go +++ b/internal/model/interfaces.go @@ -99,7 +99,7 @@ type DonatService interface { GetModerationSettings(ctx context.Context, streamerID int) (ModerationResponse, error) UpdateModerationSettings(ctx context.Context, streamerID int, updateModel UpdateModeration) error - GetDonationsStats(ctx context.Context, streamerID int, period string) ([]DonationStatResponse, error) + GetDonationsStats(ctx context.Context, streamerID int, period string) (DonationSummaryResponse, error) } type DonatRepo interface { @@ -151,6 +151,7 @@ type DonatRepo interface { UpdateModeration(ctx context.Context, streamerID int, enable *bool, duration *int) error GetDonationsStats(ctx context.Context, streamerID int, period string) ([]DonationStat, error) + GetDonationsSummary(ctx context.Context, streamerID int, period string) (DonationSummary, error) } type TargetService interface { diff --git a/internal/model/models.go b/internal/model/models.go index 6c56397..ea28d31 100644 --- a/internal/model/models.go +++ b/internal/model/models.go @@ -261,12 +261,22 @@ type DonationStat struct { DonationsCount int `db:"donations_count"` } +type DonationSummary struct { + TotalAmount int `db:"total_amount" json:"total_amount"` // Общая сумма донатов + DonationsCount int `db:"donations_count" json:"donations_count"` // Общее количество донатов +} + type DonationStatResponse struct { Date time.Time `json:"date"` AmountCollected int `json:"amount_collected"` DonationsCount int `json:"donations_count"` } +type DonationSummaryResponse struct { + DonationSum DonationSummary `json:"donation_sum"` + Donations []DonationStatResponse `json:"donations"` +} + //func (widget *GetWidgetDb) GetMediaUrl(mediaType MediaType) MediaUrl { // var mediaUrl MediaUrl // if mediaType == "background_url" { diff --git a/internal/model/sql/query.go b/internal/model/sql/query.go index 07e39bb..4891968 100644 --- a/internal/model/sql/query.go +++ b/internal/model/sql/query.go @@ -377,3 +377,47 @@ GROUP BY ORDER BY date; ` + +const GetDonationsSummaryLast24Hours = ` +SELECT + SUM(amount) AS total_amount, + COUNT(*) AS donations_count +FROM + public.donats +WHERE + streamer_id = @streamer_id + AND created_at >= NOW() - INTERVAL '24 hours'; +` + +const GetDonationsSummaryLast7Days = ` +SELECT + SUM(amount) AS total_amount, + COUNT(*) AS donations_count +FROM + public.donats +WHERE + streamer_id = @streamer_id + AND created_at >= NOW() - INTERVAL '7 days'; +` + +const GetDonationsSummaryLastMonth = ` +SELECT + SUM(amount) AS total_amount, + COUNT(*) AS donations_count +FROM + public.donats +WHERE + streamer_id = @streamer_id + AND created_at >= NOW() - INTERVAL '1 month'; +` + +const GetDonationsSummaryLastYear = ` +SELECT + SUM(amount) AS total_amount, + COUNT(*) AS donations_count +FROM + public.donats +WHERE + streamer_id = @streamer_id + AND created_at >= NOW() - INTERVAL '1 year'; +` diff --git a/internal/repository/donat/donat.go b/internal/repository/donat/donat.go index 8d2cc41..ed6eca0 100644 --- a/internal/repository/donat/donat.go +++ b/internal/repository/donat/donat.go @@ -643,3 +643,41 @@ func (repoDonat *RepoDonat) GetDonationsStats( return stats, nil } + +func (repoDonat *RepoDonat) GetDonationsSummary( + ctx context.Context, + streamerID int, + period string, // "24h", "7d", "1m", "1y" +) (model.DonationSummary, error) { + var query string + switch period { + case "24h": + query = sql.GetDonationsSummaryLast24Hours + case "7d": + query = sql.GetDonationsSummaryLast7Days + case "1m": + query = sql.GetDonationsSummaryLastMonth + case "1y": + query = sql.GetDonationsSummaryLastYear + default: + return model.DonationSummary{}, errors.New("invalid period") + } + + args := pgx.NamedArgs{ + "streamer_id": streamerID, + } + + var summary model.DonationSummary + row, err := repoDonat.db.SelectOne(ctx, query, args) + if err != nil { + slog.Error("Failed to get donations summary", "error", err) + return model.DonationSummary{}, err + } + err = row.Scan(&summary.TotalAmount, &summary.DonationsCount) + if err != nil { + slog.Error("Failed to get donations summary", "error", err) + return model.DonationSummary{}, err + } + + return summary, nil +} diff --git a/internal/service/donat/donat.go b/internal/service/donat/donat.go index bada331..c97c9d7 100644 --- a/internal/service/donat/donat.go +++ b/internal/service/donat/donat.go @@ -460,21 +460,35 @@ func (donatService *ServiceDonat) GetDonationsStats( ctx context.Context, streamerID int, period string, -) ([]model.DonationStatResponse, error) { +) (model.DonationSummaryResponse, error) { stats, err := donatService.donatRepo.GetDonationsStats(ctx, streamerID, period) if err != nil { slog.Error(err.Error()) - return nil, err + return model.DonationSummaryResponse{}, err } - var response []model.DonationStatResponse + var donationsStat []model.DonationStatResponse + var response model.DonationSummaryResponse + donationSummary, err := donatService.donatRepo.GetDonationsSummary( + ctx, + streamerID, + period, + ) + if err != nil { + slog.Error(err.Error()) + return model.DonationSummaryResponse{}, err + } + + response.DonationSum = donationSummary + for _, stat := range stats { - response = append(response, model.DonationStatResponse{ + donationsStat = append(donationsStat, model.DonationStatResponse{ Date: stat.Date, AmountCollected: stat.AmountCollected, DonationsCount: stat.DonationsCount, }) } + response.Donations = donationsStat return response, nil }