Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
|
|
@ -0,0 +1,50 @@
|
|||
package storagedailyusage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/storagedailyusage"
|
||||
)
|
||||
|
||||
// DeleteByUserUseCase deletes all storage daily usage records for a user
|
||||
// Used for GDPR right-to-be-forgotten implementation
|
||||
type DeleteByUserUseCase interface {
|
||||
Execute(ctx context.Context, userID gocql.UUID) error
|
||||
}
|
||||
|
||||
type deleteByUserUseCaseImpl struct {
|
||||
logger *zap.Logger
|
||||
repo storagedailyusage.StorageDailyUsageRepository
|
||||
}
|
||||
|
||||
// NewDeleteByUserUseCase creates a new use case for deleting all storage daily usage by user ID
|
||||
func NewDeleteByUserUseCase(
|
||||
logger *zap.Logger,
|
||||
repo storagedailyusage.StorageDailyUsageRepository,
|
||||
) DeleteByUserUseCase {
|
||||
return &deleteByUserUseCaseImpl{
|
||||
logger: logger.Named("DeleteStorageDailyUsageByUserUseCase"),
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (uc *deleteByUserUseCaseImpl) Execute(ctx context.Context, userID gocql.UUID) error {
|
||||
uc.logger.Info("Deleting all storage daily usage for user",
|
||||
zap.String("user_id", userID.String()))
|
||||
|
||||
err := uc.repo.DeleteByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
uc.logger.Error("Failed to delete storage daily usage",
|
||||
zap.String("user_id", userID.String()),
|
||||
zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
uc.logger.Info("✅ Successfully deleted all storage daily usage for user",
|
||||
zap.String("user_id", userID.String()))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package storagedailyusage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// NOTE: Unit tests for DeleteByUserUseCase would require mocks.
|
||||
// For now, this use case will be tested via integration tests.
|
||||
// See Task 1.10 in RIGHT_TO_BE_FORGOTTEN_IMPLEMENTATION.md
|
||||
|
||||
func TestDeleteByUserUseCase_Constructor(t *testing.T) {
|
||||
// Test that constructor creates use case successfully
|
||||
logger := zap.NewNop()
|
||||
|
||||
useCase := NewDeleteByUserUseCase(logger, nil)
|
||||
|
||||
if useCase == nil {
|
||||
t.Error("Expected use case to be created, got nil")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
// monorepo/cloud/maplefile-backend/internal/maplefile/usecase/storagedailyusage/get_trend.go
|
||||
package storagedailyusage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/storagedailyusage"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
|
||||
)
|
||||
|
||||
// GetStorageDailyUsageTrendRequest contains the trend parameters
|
||||
type GetStorageDailyUsageTrendRequest struct {
|
||||
UserID gocql.UUID `json:"user_id"`
|
||||
TrendPeriod string `json:"trend_period"` // "7days", "monthly", "yearly"
|
||||
Year *int `json:"year,omitempty"`
|
||||
Month *time.Month `json:"month,omitempty"`
|
||||
}
|
||||
|
||||
type GetStorageDailyUsageTrendUseCase interface {
|
||||
Execute(ctx context.Context, req *GetStorageDailyUsageTrendRequest) (*storagedailyusage.StorageUsageTrend, error)
|
||||
}
|
||||
|
||||
type getStorageDailyUsageTrendUseCaseImpl struct {
|
||||
config *config.Configuration
|
||||
logger *zap.Logger
|
||||
repo storagedailyusage.StorageDailyUsageRepository
|
||||
}
|
||||
|
||||
func NewGetStorageDailyUsageTrendUseCase(
|
||||
config *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storagedailyusage.StorageDailyUsageRepository,
|
||||
) GetStorageDailyUsageTrendUseCase {
|
||||
logger = logger.Named("GetStorageDailyUsageTrendUseCase")
|
||||
return &getStorageDailyUsageTrendUseCaseImpl{config, logger, repo}
|
||||
}
|
||||
|
||||
func (uc *getStorageDailyUsageTrendUseCaseImpl) Execute(ctx context.Context, req *GetStorageDailyUsageTrendRequest) (*storagedailyusage.StorageUsageTrend, error) {
|
||||
//
|
||||
// STEP 1: Validation.
|
||||
//
|
||||
|
||||
e := make(map[string]string)
|
||||
if req == nil {
|
||||
e["request"] = "Request is required"
|
||||
} else {
|
||||
if req.UserID.String() == "" {
|
||||
e["user_id"] = "User ID is required"
|
||||
}
|
||||
if req.TrendPeriod == "" {
|
||||
e["trend_period"] = "Trend period is required"
|
||||
} else if req.TrendPeriod != "7days" && req.TrendPeriod != "monthly" && req.TrendPeriod != "yearly" {
|
||||
e["trend_period"] = "Trend period must be one of: 7days, monthly, yearly"
|
||||
}
|
||||
|
||||
// Validate period-specific parameters
|
||||
switch req.TrendPeriod {
|
||||
case "monthly":
|
||||
if req.Year == nil {
|
||||
e["year"] = "Year is required for monthly trend"
|
||||
}
|
||||
if req.Month == nil {
|
||||
e["month"] = "Month is required for monthly trend"
|
||||
}
|
||||
case "yearly":
|
||||
if req.Year == nil {
|
||||
e["year"] = "Year is required for yearly trend"
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(e) != 0 {
|
||||
uc.logger.Warn("Failed validating get storage daily usage trend",
|
||||
zap.Any("error", e))
|
||||
return nil, httperror.NewForBadRequest(&e)
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 2: Get trend based on period.
|
||||
//
|
||||
|
||||
var trend *storagedailyusage.StorageUsageTrend
|
||||
var err error
|
||||
|
||||
switch req.TrendPeriod {
|
||||
case "7days":
|
||||
trend, err = uc.repo.GetLast7DaysTrend(ctx, req.UserID)
|
||||
|
||||
case "monthly":
|
||||
trend, err = uc.repo.GetMonthlyTrend(ctx, req.UserID, *req.Year, *req.Month)
|
||||
|
||||
case "yearly":
|
||||
trend, err = uc.repo.GetYearlyTrend(ctx, req.UserID, *req.Year)
|
||||
|
||||
default:
|
||||
return nil, httperror.NewForBadRequestWithSingleField("trend_period", "Invalid trend period")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
uc.logger.Error("Failed to get storage daily usage trend",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.String("trend_period", req.TrendPeriod),
|
||||
zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uc.logger.Debug("Successfully retrieved storage daily usage trend",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.String("trend_period", req.TrendPeriod),
|
||||
zap.Int("daily_usages_count", len(trend.DailyUsages)),
|
||||
zap.Int64("total_added", trend.TotalAdded),
|
||||
zap.Int64("total_removed", trend.TotalRemoved),
|
||||
zap.Int64("net_change", trend.NetChange))
|
||||
|
||||
return trend, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
// monorepo/cloud/maplefile-backend/internal/maplefile/usecase/storagedailyusage/get_usage_by_date_range.go
|
||||
package storagedailyusage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/storagedailyusage"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
|
||||
)
|
||||
|
||||
// GetStorageUsageByDateRangeRequest contains the date range parameters
|
||||
type GetStorageUsageByDateRangeRequest struct {
|
||||
UserID gocql.UUID `json:"user_id"`
|
||||
StartDate time.Time `json:"start_date"`
|
||||
EndDate time.Time `json:"end_date"`
|
||||
}
|
||||
|
||||
// GetStorageUsageByDateRangeResponse contains the usage data for the date range
|
||||
type GetStorageUsageByDateRangeResponse struct {
|
||||
UserID gocql.UUID `json:"user_id"`
|
||||
StartDate time.Time `json:"start_date"`
|
||||
EndDate time.Time `json:"end_date"`
|
||||
DailyUsages []*storagedailyusage.StorageDailyUsage `json:"daily_usages"`
|
||||
Summary *DateRangeSummary `json:"summary"`
|
||||
}
|
||||
|
||||
// DateRangeSummary contains aggregated statistics for the date range
|
||||
type DateRangeSummary struct {
|
||||
TotalDays int `json:"total_days"`
|
||||
DaysWithData int `json:"days_with_data"`
|
||||
TotalAdded int64 `json:"total_added"`
|
||||
TotalRemoved int64 `json:"total_removed"`
|
||||
NetChange int64 `json:"net_change"`
|
||||
AverageDailyAdd float64 `json:"average_daily_add"`
|
||||
PeakUsageDay *time.Time `json:"peak_usage_day,omitempty"`
|
||||
PeakUsageBytes int64 `json:"peak_usage_bytes"`
|
||||
LowestUsageDay *time.Time `json:"lowest_usage_day,omitempty"`
|
||||
LowestUsageBytes int64 `json:"lowest_usage_bytes"`
|
||||
}
|
||||
|
||||
type GetStorageUsageByDateRangeUseCase interface {
|
||||
Execute(ctx context.Context, req *GetStorageUsageByDateRangeRequest) (*GetStorageUsageByDateRangeResponse, error)
|
||||
}
|
||||
|
||||
type getStorageUsageByDateRangeUseCaseImpl struct {
|
||||
config *config.Configuration
|
||||
logger *zap.Logger
|
||||
repo storagedailyusage.StorageDailyUsageRepository
|
||||
}
|
||||
|
||||
func NewGetStorageUsageByDateRangeUseCase(
|
||||
config *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storagedailyusage.StorageDailyUsageRepository,
|
||||
) GetStorageUsageByDateRangeUseCase {
|
||||
logger = logger.Named("GetStorageUsageByDateRangeUseCase")
|
||||
return &getStorageUsageByDateRangeUseCaseImpl{config, logger, repo}
|
||||
}
|
||||
|
||||
func (uc *getStorageUsageByDateRangeUseCaseImpl) Execute(ctx context.Context, req *GetStorageUsageByDateRangeRequest) (*GetStorageUsageByDateRangeResponse, error) {
|
||||
//
|
||||
// STEP 1: Validation.
|
||||
//
|
||||
|
||||
e := make(map[string]string)
|
||||
if req == nil {
|
||||
e["request"] = "Request is required"
|
||||
} else {
|
||||
if req.UserID.String() == "" {
|
||||
e["user_id"] = "User ID is required"
|
||||
}
|
||||
if req.StartDate.IsZero() {
|
||||
e["start_date"] = "Start date is required"
|
||||
}
|
||||
if req.EndDate.IsZero() {
|
||||
e["end_date"] = "End date is required"
|
||||
}
|
||||
if !req.StartDate.IsZero() && !req.EndDate.IsZero() && req.StartDate.After(req.EndDate) {
|
||||
e["date_range"] = "Start date must be before or equal to end date"
|
||||
}
|
||||
// Check for reasonable date range (max 1 year)
|
||||
if !req.StartDate.IsZero() && !req.EndDate.IsZero() {
|
||||
daysDiff := int(req.EndDate.Sub(req.StartDate).Hours() / 24)
|
||||
if daysDiff > 365 {
|
||||
e["date_range"] = "Date range cannot exceed 365 days"
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(e) != 0 {
|
||||
uc.logger.Warn("Failed validating get storage usage by date range",
|
||||
zap.Any("error", e))
|
||||
return nil, httperror.NewForBadRequest(&e)
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 2: Get usage data from repository.
|
||||
//
|
||||
|
||||
// Truncate dates to ensure we're working with date-only values
|
||||
startDate := req.StartDate.Truncate(24 * time.Hour)
|
||||
endDate := req.EndDate.Truncate(24 * time.Hour)
|
||||
|
||||
dailyUsages, err := uc.repo.GetByUserDateRange(ctx, req.UserID, startDate, endDate)
|
||||
if err != nil {
|
||||
uc.logger.Error("Failed to get storage usage by date range",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.Time("start_date", startDate),
|
||||
zap.Time("end_date", endDate),
|
||||
zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 3: Generate summary statistics.
|
||||
//
|
||||
|
||||
summary := uc.generateDateRangeSummary(startDate, endDate, dailyUsages)
|
||||
|
||||
response := &GetStorageUsageByDateRangeResponse{
|
||||
UserID: req.UserID,
|
||||
StartDate: startDate,
|
||||
EndDate: endDate,
|
||||
DailyUsages: dailyUsages,
|
||||
Summary: summary,
|
||||
}
|
||||
|
||||
uc.logger.Debug("Successfully retrieved storage usage by date range",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.Time("start_date", startDate),
|
||||
zap.Time("end_date", endDate),
|
||||
zap.Int("daily_usages_count", len(dailyUsages)),
|
||||
zap.Int("days_with_data", summary.DaysWithData),
|
||||
zap.Int64("net_change", summary.NetChange))
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// generateDateRangeSummary creates summary statistics for the date range
|
||||
func (uc *getStorageUsageByDateRangeUseCaseImpl) generateDateRangeSummary(startDate, endDate time.Time, dailyUsages []*storagedailyusage.StorageDailyUsage) *DateRangeSummary {
|
||||
totalDays := int(endDate.Sub(startDate).Hours()/24) + 1
|
||||
|
||||
summary := &DateRangeSummary{
|
||||
TotalDays: totalDays,
|
||||
DaysWithData: len(dailyUsages),
|
||||
LowestUsageBytes: int64(^uint64(0) >> 1), // Max int64 value as initial
|
||||
}
|
||||
|
||||
if len(dailyUsages) == 0 {
|
||||
summary.LowestUsageBytes = 0
|
||||
return summary
|
||||
}
|
||||
|
||||
for _, usage := range dailyUsages {
|
||||
summary.TotalAdded += usage.TotalAddBytes
|
||||
summary.TotalRemoved += usage.TotalRemoveBytes
|
||||
|
||||
// Track peak usage
|
||||
if usage.TotalBytes > summary.PeakUsageBytes {
|
||||
summary.PeakUsageBytes = usage.TotalBytes
|
||||
peakDay := usage.UsageDay
|
||||
summary.PeakUsageDay = &peakDay
|
||||
}
|
||||
|
||||
// Track lowest usage
|
||||
if usage.TotalBytes < summary.LowestUsageBytes {
|
||||
summary.LowestUsageBytes = usage.TotalBytes
|
||||
lowestDay := usage.UsageDay
|
||||
summary.LowestUsageDay = &lowestDay
|
||||
}
|
||||
}
|
||||
|
||||
summary.NetChange = summary.TotalAdded - summary.TotalRemoved
|
||||
|
||||
// Calculate average daily add (only for days with data)
|
||||
if summary.DaysWithData > 0 {
|
||||
summary.AverageDailyAdd = float64(summary.TotalAdded) / float64(summary.DaysWithData)
|
||||
}
|
||||
|
||||
return summary
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
// monorepo/cloud/maplefile-backend/internal/maplefile/usecase/storagedailyusage/get_usage_summary.go
|
||||
package storagedailyusage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/storagedailyusage"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
|
||||
)
|
||||
|
||||
// GetStorageUsageSummaryRequest contains the summary parameters
|
||||
type GetStorageUsageSummaryRequest struct {
|
||||
UserID gocql.UUID `json:"user_id"`
|
||||
SummaryType string `json:"summary_type"` // "current_month", "current_year"
|
||||
}
|
||||
|
||||
type GetStorageUsageSummaryUseCase interface {
|
||||
Execute(ctx context.Context, req *GetStorageUsageSummaryRequest) (*storagedailyusage.StorageUsageSummary, error)
|
||||
}
|
||||
|
||||
type getStorageUsageSummaryUseCaseImpl struct {
|
||||
config *config.Configuration
|
||||
logger *zap.Logger
|
||||
repo storagedailyusage.StorageDailyUsageRepository
|
||||
}
|
||||
|
||||
func NewGetStorageUsageSummaryUseCase(
|
||||
config *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storagedailyusage.StorageDailyUsageRepository,
|
||||
) GetStorageUsageSummaryUseCase {
|
||||
logger = logger.Named("GetStorageUsageSummaryUseCase")
|
||||
return &getStorageUsageSummaryUseCaseImpl{config, logger, repo}
|
||||
}
|
||||
|
||||
func (uc *getStorageUsageSummaryUseCaseImpl) Execute(ctx context.Context, req *GetStorageUsageSummaryRequest) (*storagedailyusage.StorageUsageSummary, error) {
|
||||
//
|
||||
// STEP 1: Validation.
|
||||
//
|
||||
|
||||
e := make(map[string]string)
|
||||
if req == nil {
|
||||
e["request"] = "Request is required"
|
||||
} else {
|
||||
if req.UserID.String() == "" {
|
||||
e["user_id"] = "User ID is required"
|
||||
}
|
||||
if req.SummaryType == "" {
|
||||
e["summary_type"] = "Summary type is required"
|
||||
} else if req.SummaryType != "current_month" && req.SummaryType != "current_year" {
|
||||
e["summary_type"] = "Summary type must be one of: current_month, current_year"
|
||||
}
|
||||
}
|
||||
if len(e) != 0 {
|
||||
uc.logger.Warn("Failed validating get storage usage summary",
|
||||
zap.Any("error", e))
|
||||
return nil, httperror.NewForBadRequest(&e)
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 2: Get summary based on type.
|
||||
//
|
||||
|
||||
var summary *storagedailyusage.StorageUsageSummary
|
||||
var err error
|
||||
|
||||
switch req.SummaryType {
|
||||
case "current_month":
|
||||
summary, err = uc.repo.GetCurrentMonthUsage(ctx, req.UserID)
|
||||
|
||||
case "current_year":
|
||||
summary, err = uc.repo.GetCurrentYearUsage(ctx, req.UserID)
|
||||
|
||||
default:
|
||||
return nil, httperror.NewForBadRequestWithSingleField("summary_type", "Invalid summary type")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
uc.logger.Error("Failed to get storage usage summary",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.String("summary_type", req.SummaryType),
|
||||
zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uc.logger.Debug("Successfully retrieved storage usage summary",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.String("summary_type", req.SummaryType),
|
||||
zap.Int64("current_usage", summary.CurrentUsage),
|
||||
zap.Int64("total_added", summary.TotalAdded),
|
||||
zap.Int64("total_removed", summary.TotalRemoved),
|
||||
zap.Int64("net_change", summary.NetChange),
|
||||
zap.Int("days_with_data", summary.DaysWithData))
|
||||
|
||||
return summary, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package storagedailyusage
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/storagedailyusage"
|
||||
)
|
||||
|
||||
// Wire providers for storage daily usage use cases
|
||||
|
||||
func ProvideGetStorageDailyUsageTrendUseCase(
|
||||
cfg *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storagedailyusage.StorageDailyUsageRepository,
|
||||
) GetStorageDailyUsageTrendUseCase {
|
||||
return NewGetStorageDailyUsageTrendUseCase(cfg, logger, repo)
|
||||
}
|
||||
|
||||
func ProvideGetStorageUsageSummaryUseCase(
|
||||
cfg *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storagedailyusage.StorageDailyUsageRepository,
|
||||
) GetStorageUsageSummaryUseCase {
|
||||
return NewGetStorageUsageSummaryUseCase(cfg, logger, repo)
|
||||
}
|
||||
|
||||
func ProvideGetStorageUsageByDateRangeUseCase(
|
||||
cfg *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storagedailyusage.StorageDailyUsageRepository,
|
||||
) GetStorageUsageByDateRangeUseCase {
|
||||
return NewGetStorageUsageByDateRangeUseCase(cfg, logger, repo)
|
||||
}
|
||||
|
||||
func ProvideUpdateStorageUsageUseCase(
|
||||
cfg *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storagedailyusage.StorageDailyUsageRepository,
|
||||
) UpdateStorageUsageUseCase {
|
||||
return NewUpdateStorageUsageUseCase(cfg, logger, repo)
|
||||
}
|
||||
|
||||
func ProvideDeleteByUserUseCase(
|
||||
logger *zap.Logger,
|
||||
repo storagedailyusage.StorageDailyUsageRepository,
|
||||
) DeleteByUserUseCase {
|
||||
return NewDeleteByUserUseCase(logger, repo)
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
// monorepo/cloud/maplefile-backend/internal/maplefile/usecase/storagedailyusage/update_usage.go
|
||||
package storagedailyusage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/storagedailyusage"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
|
||||
)
|
||||
|
||||
// UpdateStorageUsageRequest contains the update parameters
|
||||
type UpdateStorageUsageRequest struct {
|
||||
UserID gocql.UUID `json:"user_id"`
|
||||
UsageDay *time.Time `json:"usage_day,omitempty"` // Optional, defaults to today
|
||||
TotalBytes int64 `json:"total_bytes"`
|
||||
AddBytes int64 `json:"add_bytes"`
|
||||
RemoveBytes int64 `json:"remove_bytes"`
|
||||
IsIncrement bool `json:"is_increment"` // If true, increment existing values; if false, set absolute values
|
||||
}
|
||||
|
||||
type UpdateStorageUsageUseCase interface {
|
||||
Execute(ctx context.Context, req *UpdateStorageUsageRequest) error
|
||||
}
|
||||
|
||||
type updateStorageUsageUseCaseImpl struct {
|
||||
config *config.Configuration
|
||||
logger *zap.Logger
|
||||
repo storagedailyusage.StorageDailyUsageRepository
|
||||
}
|
||||
|
||||
func NewUpdateStorageUsageUseCase(
|
||||
config *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storagedailyusage.StorageDailyUsageRepository,
|
||||
) UpdateStorageUsageUseCase {
|
||||
logger = logger.Named("UpdateStorageUsageUseCase")
|
||||
return &updateStorageUsageUseCaseImpl{config, logger, repo}
|
||||
}
|
||||
|
||||
func (uc *updateStorageUsageUseCaseImpl) Execute(ctx context.Context, req *UpdateStorageUsageRequest) error {
|
||||
//
|
||||
// STEP 1: Validation.
|
||||
//
|
||||
|
||||
e := make(map[string]string)
|
||||
if req == nil {
|
||||
e["request"] = "Request is required"
|
||||
} else {
|
||||
if req.UserID.String() == "" {
|
||||
e["user_id"] = "User ID is required"
|
||||
}
|
||||
if req.AddBytes < 0 {
|
||||
e["add_bytes"] = "Add bytes cannot be negative"
|
||||
}
|
||||
if req.RemoveBytes < 0 {
|
||||
e["remove_bytes"] = "Remove bytes cannot be negative"
|
||||
}
|
||||
if !req.IsIncrement && req.TotalBytes < 0 {
|
||||
e["total_bytes"] = "Total bytes cannot be negative when setting absolute values"
|
||||
}
|
||||
}
|
||||
if len(e) != 0 {
|
||||
uc.logger.Warn("Failed validating update storage usage",
|
||||
zap.Any("error", e))
|
||||
return httperror.NewForBadRequest(&e)
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 2: Set usage day if not provided.
|
||||
//
|
||||
|
||||
usageDay := time.Now().Truncate(24 * time.Hour)
|
||||
if req.UsageDay != nil {
|
||||
usageDay = req.UsageDay.Truncate(24 * time.Hour)
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 3: Update or increment usage.
|
||||
//
|
||||
|
||||
var err error
|
||||
|
||||
if req.IsIncrement {
|
||||
// Increment existing values
|
||||
err = uc.repo.IncrementUsage(ctx, req.UserID, usageDay, req.TotalBytes, req.AddBytes, req.RemoveBytes)
|
||||
} else {
|
||||
// Set absolute values
|
||||
usage := &storagedailyusage.StorageDailyUsage{
|
||||
UserID: req.UserID,
|
||||
UsageDay: usageDay,
|
||||
TotalBytes: req.TotalBytes,
|
||||
TotalAddBytes: req.AddBytes,
|
||||
TotalRemoveBytes: req.RemoveBytes,
|
||||
}
|
||||
err = uc.repo.UpdateOrCreate(ctx, usage)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
uc.logger.Error("Failed to update storage usage",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.Time("usage_day", usageDay),
|
||||
zap.Int64("total_bytes", req.TotalBytes),
|
||||
zap.Int64("add_bytes", req.AddBytes),
|
||||
zap.Int64("remove_bytes", req.RemoveBytes),
|
||||
zap.Bool("is_increment", req.IsIncrement),
|
||||
zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
uc.logger.Debug("Successfully updated storage usage",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.Time("usage_day", usageDay),
|
||||
zap.Int64("total_bytes", req.TotalBytes),
|
||||
zap.Int64("add_bytes", req.AddBytes),
|
||||
zap.Int64("remove_bytes", req.RemoveBytes),
|
||||
zap.Bool("is_increment", req.IsIncrement))
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue