Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions s3manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,14 @@ func (m *S3Manager) GenerateS3Key(userID, contactJID, messageID string, mimeType
contactJID = strings.ReplaceAll(contactJID, "@", "_")
contactJID = strings.ReplaceAll(contactJID, ":", "_")

// Get current time
// Get current time. Go's reference time is "2006-01-02 15:04:05", so the
// layout tokens for year/month/day are "2006"/"01"/"02". The previous
// values ("2025"/"05"/"25") were not valid tokens — "05" is the seconds
// field — so media was filed under nonsensical, non-chronological folders.
now := time.Now()
year := now.Format("2025")
month := now.Format("05")
day := now.Format("25")
year := now.Format("2006")
month := now.Format("01")
day := now.Format("02")

// Determine media type folder
mediaType := "documents"
Expand Down
43 changes: 43 additions & 0 deletions s3manager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"strings"
"testing"
"time"
)

// TestGenerateS3KeyDateFormat verifies the fix for the S3 key date path: the
// year/month/day segments must use valid Go layout tokens ("2006"/"01"/"02").
// The previous code used "2025"/"05"/"25", which are not valid tokens ("05" is
// the seconds field), producing a 5-digit "year" and nonsensical month/day.
func TestGenerateS3KeyDateFormat(t *testing.T) {
m := &S3Manager{}
key := m.GenerateS3Key("user-1", "123456@s.whatsapp.net", "MSGID", "image/jpeg", true)

// Layout: users/{userID}/{direction}/{contactJID}/{year}/{month}/{day}/{mediaType}/{messageID}{ext}
parts := strings.Split(key, "/")
if len(parts) != 9 {
t.Fatalf("unexpected key shape %q (%d segments, want 9)", key, len(parts))
}
year, month, day := parts[4], parts[5], parts[6]

now := time.Now()
if want := now.Format("2006"); year != want {
t.Errorf("year segment = %q, want %q (key=%q)", year, want, key)
}
if want := now.Format("01"); month != want {
t.Errorf("month segment = %q, want %q (key=%q)", month, want, key)
}
if want := now.Format("02"); day != want {
t.Errorf("day segment = %q, want %q (key=%q)", day, want, key)
}

// Regression guard independent of the current date: the old bug produced a
// 5-digit "year" and a "month" rendered from seconds. Enforce exact widths.
if len(year) != 4 {
t.Errorf("year segment %q must be exactly 4 digits (key=%q)", year, key)
}
if len(month) != 2 || len(day) != 2 {
t.Errorf("month/day segments must be 2 digits, got %q/%q (key=%q)", month, day, key)
}
}