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,87 @@
|
|||
// monorepo/cloud/maplefile-backend/internal/maplefile/usecase/storageusageevent/create_event.go
|
||||
package storageusageevent
|
||||
|
||||
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/storageusageevent"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
|
||||
)
|
||||
|
||||
type CreateStorageUsageEventUseCase interface {
|
||||
Execute(ctx context.Context, userID gocql.UUID, fileSize int64, operation string) error
|
||||
}
|
||||
|
||||
type createStorageUsageEventUseCaseImpl struct {
|
||||
config *config.Configuration
|
||||
logger *zap.Logger
|
||||
repo storageusageevent.StorageUsageEventRepository
|
||||
}
|
||||
|
||||
func NewCreateStorageUsageEventUseCase(
|
||||
config *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storageusageevent.StorageUsageEventRepository,
|
||||
) CreateStorageUsageEventUseCase {
|
||||
logger = logger.Named("CreateStorageUsageEventUseCase")
|
||||
return &createStorageUsageEventUseCaseImpl{config, logger, repo}
|
||||
}
|
||||
|
||||
func (uc *createStorageUsageEventUseCaseImpl) Execute(ctx context.Context, userID gocql.UUID, fileSize int64, operation string) error {
|
||||
//
|
||||
// STEP 1: Validation.
|
||||
//
|
||||
|
||||
e := make(map[string]string)
|
||||
if userID.String() == "" {
|
||||
e["user_id"] = "User ID is required"
|
||||
}
|
||||
if fileSize <= 0 {
|
||||
e["file_size"] = "File size must be greater than 0"
|
||||
}
|
||||
if operation == "" {
|
||||
e["operation"] = "Operation is required"
|
||||
} else if operation != "add" && operation != "remove" {
|
||||
e["operation"] = "Operation must be 'add' or 'remove'"
|
||||
}
|
||||
if len(e) != 0 {
|
||||
uc.logger.Warn("Failed validating create storage usage event",
|
||||
zap.Any("error", e))
|
||||
return httperror.NewForBadRequest(&e)
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 2: Create storage usage event.
|
||||
//
|
||||
|
||||
now := time.Now()
|
||||
event := &storageusageevent.StorageUsageEvent{
|
||||
UserID: userID,
|
||||
EventDay: now.Truncate(24 * time.Hour),
|
||||
EventTime: now,
|
||||
FileSize: fileSize,
|
||||
Operation: operation,
|
||||
}
|
||||
|
||||
err := uc.repo.Create(ctx, event)
|
||||
if err != nil {
|
||||
uc.logger.Error("Failed to create storage usage event",
|
||||
zap.String("user_id", userID.String()),
|
||||
zap.Int64("file_size", fileSize),
|
||||
zap.String("operation", operation),
|
||||
zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
uc.logger.Debug("Successfully created storage usage event",
|
||||
zap.String("user_id", userID.String()),
|
||||
zap.Int64("file_size", fileSize),
|
||||
zap.String("operation", operation))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package storageusageevent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/storageusageevent"
|
||||
)
|
||||
|
||||
// DeleteByUserUseCase deletes all storage usage events 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 storageusageevent.StorageUsageEventRepository
|
||||
}
|
||||
|
||||
// NewDeleteByUserUseCase creates a new use case for deleting all storage usage events by user ID
|
||||
func NewDeleteByUserUseCase(
|
||||
logger *zap.Logger,
|
||||
repo storageusageevent.StorageUsageEventRepository,
|
||||
) DeleteByUserUseCase {
|
||||
return &deleteByUserUseCaseImpl{
|
||||
logger: logger.Named("DeleteStorageUsageEventByUserUseCase"),
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (uc *deleteByUserUseCaseImpl) Execute(ctx context.Context, userID gocql.UUID) error {
|
||||
uc.logger.Info("Deleting all storage usage events for user",
|
||||
zap.String("user_id", userID.String()))
|
||||
|
||||
err := uc.repo.DeleteByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
uc.logger.Error("Failed to delete storage usage events",
|
||||
zap.String("user_id", userID.String()),
|
||||
zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
uc.logger.Info("✅ Successfully deleted all storage usage events for user",
|
||||
zap.String("user_id", userID.String()))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package storageusageevent
|
||||
|
||||
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,159 @@
|
|||
// monorepo/cloud/maplefile-backend/internal/maplefile/usecase/storageusageevent/get_events.go
|
||||
package storageusageevent
|
||||
|
||||
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/storageusageevent"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
|
||||
)
|
||||
|
||||
// GetStorageUsageEventsRequest contains the filtering parameters
|
||||
type GetStorageUsageEventsRequest 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"`
|
||||
Days *int `json:"days,omitempty"` // For custom day ranges
|
||||
}
|
||||
|
||||
// GetStorageUsageEventsResponse contains the filtered events
|
||||
type GetStorageUsageEventsResponse struct {
|
||||
UserID gocql.UUID `json:"user_id"`
|
||||
TrendPeriod string `json:"trend_period"`
|
||||
StartDate time.Time `json:"start_date"`
|
||||
EndDate time.Time `json:"end_date"`
|
||||
Events []*storageusageevent.StorageUsageEvent `json:"events"`
|
||||
EventCount int `json:"event_count"`
|
||||
}
|
||||
|
||||
type GetStorageUsageEventsUseCase interface {
|
||||
Execute(ctx context.Context, req *GetStorageUsageEventsRequest) (*GetStorageUsageEventsResponse, error)
|
||||
}
|
||||
|
||||
type getStorageUsageEventsUseCaseImpl struct {
|
||||
config *config.Configuration
|
||||
logger *zap.Logger
|
||||
repo storageusageevent.StorageUsageEventRepository
|
||||
}
|
||||
|
||||
func NewGetStorageUsageEventsUseCase(
|
||||
config *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storageusageevent.StorageUsageEventRepository,
|
||||
) GetStorageUsageEventsUseCase {
|
||||
logger = logger.Named("GetStorageUsageEventsUseCase")
|
||||
return &getStorageUsageEventsUseCaseImpl{config, logger, repo}
|
||||
}
|
||||
|
||||
func (uc *getStorageUsageEventsUseCaseImpl) Execute(ctx context.Context, req *GetStorageUsageEventsRequest) (*GetStorageUsageEventsResponse, 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" && req.TrendPeriod != "custom" {
|
||||
e["trend_period"] = "Trend period must be one of: 7days, monthly, yearly, custom"
|
||||
}
|
||||
|
||||
// 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"
|
||||
}
|
||||
case "custom":
|
||||
if req.Days == nil || *req.Days <= 0 {
|
||||
e["days"] = "Days must be greater than 0 for custom trend"
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(e) != 0 {
|
||||
uc.logger.Warn("Failed validating get storage usage events",
|
||||
zap.Any("error", e))
|
||||
return nil, httperror.NewForBadRequest(&e)
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 2: Get events based on trend period.
|
||||
//
|
||||
|
||||
var events []*storageusageevent.StorageUsageEvent
|
||||
var err error
|
||||
var startDate, endDate time.Time
|
||||
|
||||
switch req.TrendPeriod {
|
||||
case "7days":
|
||||
events, err = uc.repo.GetLast7DaysEvents(ctx, req.UserID)
|
||||
endDate = time.Now().Truncate(24 * time.Hour)
|
||||
startDate = endDate.Add(-6 * 24 * time.Hour)
|
||||
|
||||
case "monthly":
|
||||
events, err = uc.repo.GetMonthlyEvents(ctx, req.UserID, *req.Year, *req.Month)
|
||||
startDate = time.Date(*req.Year, *req.Month, 1, 0, 0, 0, 0, time.UTC)
|
||||
endDate = startDate.AddDate(0, 1, -1) // Last day of the month
|
||||
|
||||
case "yearly":
|
||||
events, err = uc.repo.GetYearlyEvents(ctx, req.UserID, *req.Year)
|
||||
startDate = time.Date(*req.Year, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
endDate = time.Date(*req.Year, 12, 31, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
case "custom":
|
||||
events, err = uc.repo.GetLastNDaysEvents(ctx, req.UserID, *req.Days)
|
||||
endDate = time.Now().Truncate(24 * time.Hour)
|
||||
startDate = endDate.Add(-time.Duration(*req.Days-1) * 24 * time.Hour)
|
||||
|
||||
default:
|
||||
return nil, httperror.NewForBadRequestWithSingleField("trend_period", "Invalid trend period")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
uc.logger.Error("Failed to get storage usage events",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.String("trend_period", req.TrendPeriod),
|
||||
zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 3: Build response.
|
||||
//
|
||||
|
||||
response := &GetStorageUsageEventsResponse{
|
||||
UserID: req.UserID,
|
||||
TrendPeriod: req.TrendPeriod,
|
||||
StartDate: startDate,
|
||||
EndDate: endDate,
|
||||
Events: events,
|
||||
EventCount: len(events),
|
||||
}
|
||||
|
||||
uc.logger.Debug("Successfully retrieved storage usage events",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.String("trend_period", req.TrendPeriod),
|
||||
zap.Int("event_count", len(events)),
|
||||
zap.Time("start_date", startDate),
|
||||
zap.Time("end_date", endDate))
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
// monorepo/cloud/maplefile-backend/internal/maplefile/usecase/storageusageevent/get_trend_analysis.go
|
||||
package storageusageevent
|
||||
|
||||
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/storageusageevent"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
|
||||
)
|
||||
|
||||
// StorageEventTrendAnalysis contains aggregated trend data
|
||||
type StorageEventTrendAnalysis struct {
|
||||
UserID gocql.UUID `json:"user_id"`
|
||||
TrendPeriod string `json:"trend_period"`
|
||||
StartDate time.Time `json:"start_date"`
|
||||
EndDate time.Time `json:"end_date"`
|
||||
TotalEvents int `json:"total_events"`
|
||||
AddEvents int `json:"add_events"`
|
||||
RemoveEvents int `json:"remove_events"`
|
||||
TotalBytesAdded int64 `json:"total_bytes_added"`
|
||||
TotalBytesRemoved int64 `json:"total_bytes_removed"`
|
||||
NetBytesChange int64 `json:"net_bytes_change"`
|
||||
AverageBytesPerAdd float64 `json:"average_bytes_per_add"`
|
||||
AverageBytesPerRemove float64 `json:"average_bytes_per_remove"`
|
||||
LargestAddEvent int64 `json:"largest_add_event"`
|
||||
LargestRemoveEvent int64 `json:"largest_remove_event"`
|
||||
DailyBreakdown []DailyStats `json:"daily_breakdown,omitempty"`
|
||||
}
|
||||
|
||||
// DailyStats represents daily aggregated statistics
|
||||
type DailyStats struct {
|
||||
Date time.Time `json:"date"`
|
||||
AddEvents int `json:"add_events"`
|
||||
RemoveEvents int `json:"remove_events"`
|
||||
BytesAdded int64 `json:"bytes_added"`
|
||||
BytesRemoved int64 `json:"bytes_removed"`
|
||||
NetChange int64 `json:"net_change"`
|
||||
}
|
||||
|
||||
type GetStorageUsageEventsTrendAnalysisUseCase interface {
|
||||
Execute(ctx context.Context, req *GetStorageUsageEventsRequest) (*StorageEventTrendAnalysis, error)
|
||||
}
|
||||
|
||||
type getStorageUsageEventsTrendAnalysisUseCaseImpl struct {
|
||||
config *config.Configuration
|
||||
logger *zap.Logger
|
||||
repo storageusageevent.StorageUsageEventRepository
|
||||
}
|
||||
|
||||
func NewGetStorageUsageEventsTrendAnalysisUseCase(
|
||||
config *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storageusageevent.StorageUsageEventRepository,
|
||||
) GetStorageUsageEventsTrendAnalysisUseCase {
|
||||
logger = logger.Named("GetStorageUsageEventsTrendAnalysisUseCase")
|
||||
return &getStorageUsageEventsTrendAnalysisUseCaseImpl{config, logger, repo}
|
||||
}
|
||||
|
||||
func (uc *getStorageUsageEventsTrendAnalysisUseCaseImpl) Execute(ctx context.Context, req *GetStorageUsageEventsRequest) (*StorageEventTrendAnalysis, error) {
|
||||
//
|
||||
// STEP 1: Validation (reuse from GetStorageUsageEventsUseCase).
|
||||
//
|
||||
|
||||
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" && req.TrendPeriod != "custom" {
|
||||
e["trend_period"] = "Trend period must be one of: 7days, monthly, yearly, custom"
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
case "custom":
|
||||
if req.Days == nil || *req.Days <= 0 {
|
||||
e["days"] = "Days must be greater than 0 for custom trend"
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(e) != 0 {
|
||||
uc.logger.Warn("Failed validating get storage usage events trend analysis",
|
||||
zap.Any("error", e))
|
||||
return nil, httperror.NewForBadRequest(&e)
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 2: Get events based on trend period.
|
||||
//
|
||||
|
||||
var events []*storageusageevent.StorageUsageEvent
|
||||
var err error
|
||||
var startDate, endDate time.Time
|
||||
|
||||
switch req.TrendPeriod {
|
||||
case "7days":
|
||||
events, err = uc.repo.GetLast7DaysEvents(ctx, req.UserID)
|
||||
endDate = time.Now().Truncate(24 * time.Hour)
|
||||
startDate = endDate.Add(-6 * 24 * time.Hour)
|
||||
|
||||
case "monthly":
|
||||
events, err = uc.repo.GetMonthlyEvents(ctx, req.UserID, *req.Year, *req.Month)
|
||||
startDate = time.Date(*req.Year, *req.Month, 1, 0, 0, 0, 0, time.UTC)
|
||||
endDate = startDate.AddDate(0, 1, -1)
|
||||
|
||||
case "yearly":
|
||||
events, err = uc.repo.GetYearlyEvents(ctx, req.UserID, *req.Year)
|
||||
startDate = time.Date(*req.Year, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
endDate = time.Date(*req.Year, 12, 31, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
case "custom":
|
||||
events, err = uc.repo.GetLastNDaysEvents(ctx, req.UserID, *req.Days)
|
||||
endDate = time.Now().Truncate(24 * time.Hour)
|
||||
startDate = endDate.Add(-time.Duration(*req.Days-1) * 24 * time.Hour)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
uc.logger.Error("Failed to get storage usage events for trend analysis",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.String("trend_period", req.TrendPeriod),
|
||||
zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 3: Analyze events and build trend analysis.
|
||||
//
|
||||
|
||||
analysis := uc.analyzeEvents(req.UserID, req.TrendPeriod, startDate, endDate, events)
|
||||
|
||||
uc.logger.Debug("Successfully analyzed storage usage events trend",
|
||||
zap.String("user_id", req.UserID.String()),
|
||||
zap.String("trend_period", req.TrendPeriod),
|
||||
zap.Int("total_events", analysis.TotalEvents),
|
||||
zap.Int64("net_bytes_change", analysis.NetBytesChange))
|
||||
|
||||
return analysis, nil
|
||||
}
|
||||
|
||||
// analyzeEvents processes the events and generates trend analysis
|
||||
func (uc *getStorageUsageEventsTrendAnalysisUseCaseImpl) analyzeEvents(userID gocql.UUID, trendPeriod string, startDate, endDate time.Time, events []*storageusageevent.StorageUsageEvent) *StorageEventTrendAnalysis {
|
||||
analysis := &StorageEventTrendAnalysis{
|
||||
UserID: userID,
|
||||
TrendPeriod: trendPeriod,
|
||||
StartDate: startDate,
|
||||
EndDate: endDate,
|
||||
}
|
||||
|
||||
if len(events) == 0 {
|
||||
return analysis
|
||||
}
|
||||
|
||||
// Daily breakdown map
|
||||
dailyMap := make(map[string]*DailyStats)
|
||||
|
||||
// Process each event
|
||||
for _, event := range events {
|
||||
analysis.TotalEvents++
|
||||
|
||||
if event.Operation == "add" {
|
||||
analysis.AddEvents++
|
||||
analysis.TotalBytesAdded += event.FileSize
|
||||
if event.FileSize > analysis.LargestAddEvent {
|
||||
analysis.LargestAddEvent = event.FileSize
|
||||
}
|
||||
} else if event.Operation == "remove" {
|
||||
analysis.RemoveEvents++
|
||||
analysis.TotalBytesRemoved += event.FileSize
|
||||
if event.FileSize > analysis.LargestRemoveEvent {
|
||||
analysis.LargestRemoveEvent = event.FileSize
|
||||
}
|
||||
}
|
||||
|
||||
// Daily breakdown
|
||||
dayKey := event.EventDay.Format("2006-01-02")
|
||||
if dailyMap[dayKey] == nil {
|
||||
dailyMap[dayKey] = &DailyStats{
|
||||
Date: event.EventDay,
|
||||
}
|
||||
}
|
||||
|
||||
daily := dailyMap[dayKey]
|
||||
if event.Operation == "add" {
|
||||
daily.AddEvents++
|
||||
daily.BytesAdded += event.FileSize
|
||||
} else if event.Operation == "remove" {
|
||||
daily.RemoveEvents++
|
||||
daily.BytesRemoved += event.FileSize
|
||||
}
|
||||
daily.NetChange = daily.BytesAdded - daily.BytesRemoved
|
||||
}
|
||||
|
||||
// Calculate derived metrics
|
||||
analysis.NetBytesChange = analysis.TotalBytesAdded - analysis.TotalBytesRemoved
|
||||
|
||||
if analysis.AddEvents > 0 {
|
||||
analysis.AverageBytesPerAdd = float64(analysis.TotalBytesAdded) / float64(analysis.AddEvents)
|
||||
}
|
||||
|
||||
if analysis.RemoveEvents > 0 {
|
||||
analysis.AverageBytesPerRemove = float64(analysis.TotalBytesRemoved) / float64(analysis.RemoveEvents)
|
||||
}
|
||||
|
||||
// Convert daily map to slice and sort by date
|
||||
for _, daily := range dailyMap {
|
||||
analysis.DailyBreakdown = append(analysis.DailyBreakdown, *daily)
|
||||
}
|
||||
|
||||
// Sort daily breakdown by date
|
||||
for i := 0; i < len(analysis.DailyBreakdown)-1; i++ {
|
||||
for j := i + 1; j < len(analysis.DailyBreakdown); j++ {
|
||||
if analysis.DailyBreakdown[i].Date.After(analysis.DailyBreakdown[j].Date) {
|
||||
analysis.DailyBreakdown[i], analysis.DailyBreakdown[j] = analysis.DailyBreakdown[j], analysis.DailyBreakdown[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return analysis
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package storageusageevent
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/storageusageevent"
|
||||
)
|
||||
|
||||
// Wire providers for storage usage event use cases
|
||||
|
||||
func ProvideCreateStorageUsageEventUseCase(
|
||||
cfg *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storageusageevent.StorageUsageEventRepository,
|
||||
) CreateStorageUsageEventUseCase {
|
||||
return NewCreateStorageUsageEventUseCase(cfg, logger, repo)
|
||||
}
|
||||
|
||||
func ProvideGetStorageUsageEventsUseCase(
|
||||
cfg *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storageusageevent.StorageUsageEventRepository,
|
||||
) GetStorageUsageEventsUseCase {
|
||||
return NewGetStorageUsageEventsUseCase(cfg, logger, repo)
|
||||
}
|
||||
|
||||
func ProvideGetStorageUsageEventsTrendAnalysisUseCase(
|
||||
cfg *config.Configuration,
|
||||
logger *zap.Logger,
|
||||
repo storageusageevent.StorageUsageEventRepository,
|
||||
) GetStorageUsageEventsTrendAnalysisUseCase {
|
||||
return NewGetStorageUsageEventsTrendAnalysisUseCase(cfg, logger, repo)
|
||||
}
|
||||
|
||||
func ProvideDeleteByUserUseCase(
|
||||
logger *zap.Logger,
|
||||
repo storageusageevent.StorageUsageEventRepository,
|
||||
) DeleteByUserUseCase {
|
||||
return NewDeleteByUserUseCase(logger, repo)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue