87 lines
3.2 KiB
Go
87 lines
3.2 KiB
Go
// monorepo/cloud/maplefile-backend/internal/maplefile/repo/storageusageevent/delete.go
|
|
package storageusageevent
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/gocql/gocql"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func (impl *storageUsageEventRepositoryImpl) DeleteByUserAndDay(ctx context.Context, userID gocql.UUID, eventDay time.Time) error {
|
|
// Ensure event day is truncated to date only
|
|
eventDay = eventDay.Truncate(24 * time.Hour)
|
|
|
|
query := `DELETE FROM maplefile.storage_usage_events_by_user_id_and_event_day_with_asc_event_time
|
|
WHERE user_id = ? AND event_day = ?`
|
|
|
|
err := impl.Session.Query(query, userID, eventDay).WithContext(ctx).Exec()
|
|
if err != nil {
|
|
impl.Logger.Error("failed to delete storage usage events by user and day", zap.Error(err))
|
|
return fmt.Errorf("failed to delete storage usage events: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DeleteByUserID deletes all storage usage events for a user (all days)
|
|
// Used for GDPR right-to-be-forgotten implementation
|
|
//
|
|
// NOTE: Because storage_usage_events table is partitioned by (user_id, event_day),
|
|
// we need to query to find all event_day values first, then delete each partition.
|
|
// For efficiency, we'll delete up to 2 years of data (should cover most reasonable usage).
|
|
func (impl *storageUsageEventRepositoryImpl) DeleteByUserID(ctx context.Context, userID gocql.UUID) error {
|
|
// Delete events from the last 2 years (730 days)
|
|
// This should cover all reasonable user data retention periods
|
|
endDay := time.Now().Truncate(24 * time.Hour)
|
|
startDay := endDay.Add(-730 * 24 * time.Hour) // 2 years ago
|
|
|
|
impl.Logger.Info("Deleting storage usage events for user",
|
|
zap.String("user_id", userID.String()),
|
|
zap.Time("start_day", startDay),
|
|
zap.Time("end_day", endDay))
|
|
|
|
// Use batch delete for efficiency
|
|
batch := impl.Session.NewBatch(gocql.LoggedBatch).WithContext(ctx)
|
|
deletedDays := 0
|
|
|
|
// Delete each day's partition
|
|
for day := startDay; !day.After(endDay); day = day.Add(24 * time.Hour) {
|
|
query := `DELETE FROM maplefile.storage_usage_events_by_user_id_and_event_day_with_asc_event_time
|
|
WHERE user_id = ? AND event_day = ?`
|
|
batch.Query(query, userID, day)
|
|
deletedDays++
|
|
|
|
// Execute batch every 100 days to avoid batch size limits
|
|
if deletedDays%100 == 0 {
|
|
if err := impl.Session.ExecuteBatch(batch); err != nil {
|
|
impl.Logger.Error("failed to execute batch delete for storage usage events",
|
|
zap.String("user_id", userID.String()),
|
|
zap.Int("days_in_batch", 100),
|
|
zap.Error(err))
|
|
return fmt.Errorf("failed to delete storage usage events for user %s: %w", userID.String(), err)
|
|
}
|
|
// Create new batch for next set of days
|
|
batch = impl.Session.NewBatch(gocql.LoggedBatch).WithContext(ctx)
|
|
}
|
|
}
|
|
|
|
// Execute remaining batch
|
|
if batch.Size() > 0 {
|
|
if err := impl.Session.ExecuteBatch(batch); err != nil {
|
|
impl.Logger.Error("failed to execute final batch delete for storage usage events",
|
|
zap.String("user_id", userID.String()),
|
|
zap.Int("days_in_final_batch", batch.Size()),
|
|
zap.Error(err))
|
|
return fmt.Errorf("failed to delete storage usage events for user %s: %w", userID.String(), err)
|
|
}
|
|
}
|
|
|
|
impl.Logger.Info("✅ Deleted all storage usage events for user",
|
|
zap.String("user_id", userID.String()),
|
|
zap.Int("total_days_deleted", deletedDays))
|
|
|
|
return nil
|
|
}
|