@@ -27,13 +27,13 @@ const (
2727
2828// SignatureRecord represents the DynamoDB signature record structure
2929type SignatureRecord struct {
30- SignatureID string `dynamodbav:"signature_id"`
31- DateCreated string `dynamodbav:"date_created"`
32- ApproxDateCreated string `dynamodbav:"approx_date_created"`
33- SignatureType string `dynamodbav:"signature_type"`
34- SigtypeSignedApprovedID string `dynamodbav:"sigtype_signed_approved_id"`
35- SignatureApproved bool `dynamodbav:"signature_approved"`
36- SignatureSigned bool `dynamodbav:"signature_signed"`
30+ SignatureID string `dynamodbav:"signature_id"`
31+ DateCreated string `dynamodbav:"date_created"`
32+ ApproxDateCreated string `dynamodbav:"approx_date_created"`
33+ SignatureType string `dynamodbav:"signature_type"`
34+ SigtypeSignedApprovedID string `dynamodbav:"sigtype_signed_approved_id"`
35+ SignatureApproved bool `dynamodbav:"signature_approved"`
36+ SignatureSigned bool `dynamodbav:"signature_signed"`
3737}
3838
3939// MonthlyStats holds the count of signatures per month
@@ -64,8 +64,24 @@ func main() {
6464 monthlyStats := make (map [string ]* MonthlyStats )
6565
6666 // Scan parameters
67+ // Full attributes scan
68+ // params := &dynamodb.ScanInput{TableName: aws.String(tableName)}
69+ // Scan only needed parameters
6770 params := & dynamodb.ScanInput {
6871 TableName : aws .String (tableName ),
72+ // Only fetch the fields we actually need
73+ ProjectionExpression : aws .String (
74+ "#sid, #dc, #adc, #st, #ssa, #sa, #ss" ,
75+ ),
76+ ExpressionAttributeNames : map [string ]* string {
77+ "#sid" : aws .String ("signature_id" ),
78+ "#dc" : aws .String ("date_created" ),
79+ "#adc" : aws .String ("approx_date_created" ),
80+ "#st" : aws .String ("signature_type" ),
81+ "#ssa" : aws .String ("sigtype_signed_approved_id" ),
82+ "#sa" : aws .String ("signature_approved" ),
83+ "#ss" : aws .String ("signature_signed" ),
84+ },
6985 }
7086
7187 // Get current time for validation
@@ -109,21 +125,22 @@ func main() {
109125 }
110126
111127 // Parse creation date to extract month
112- month := extractMonth (creationDate , currentMonth )
128+ month := extractMonth (creationDate )
113129 if month == "" {
114130 skippedInvalidDates ++
115131 continue
116132 }
117133
118134 // Check if month is in the future
135+ // Month and currentMonth are formatted as YYYY-MM, so string comparison is safe
119136 if month > currentMonth {
120137 skippedFutureDates ++
121138 continue
122139 }
123140
124141 // Determine signature type based on multiple factors
125142 var isICLA , isECLA , isCCLA bool
126-
143+
127144 // Primary method: check sigtype_signed_approved_id
128145 if sig .SigtypeSignedApprovedID != "" {
129146 if strings .HasPrefix (sig .SigtypeSignedApprovedID , "icla#" ) {
@@ -142,7 +159,7 @@ func main() {
142159 } else if sig .SignatureType != "" {
143160 // Fallback method: check signature_type field
144161 switch sig .SignatureType {
145- case "cla" :
162+ case "cla" , "icla" :
146163 // For legacy CLA records without sigtype_signed_approved_id, treat as ICLA
147164 isICLA = true
148165 totalICLA ++
@@ -208,13 +225,14 @@ func main() {
208225 defer file .Close ()
209226
210227 writer := csv .NewWriter (file )
211- defer writer .Flush ()
212228
213229 // Set semicolon as separator
214230 writer .Comma = ';'
215231
216232 // Write header
217- writer .Write ([]string {"month" , "ICLAs" , "ECLAs" , "CCLAs" })
233+ if err := writer .Write ([]string {"month" , "ICLAs" , "ECLAs" , "CCLAs" }); err != nil {
234+ log .Fatalf ("Error writing CSV header: %v" , err )
235+ }
218236
219237 // Write data
220238 for _ , stats := range monthlyData {
@@ -224,23 +242,29 @@ func main() {
224242 strconv .Itoa (stats .ECLA ),
225243 strconv .Itoa (stats .CCLA ),
226244 }
227- writer .Write (record )
245+ if err := writer .Write (record ); err != nil {
246+ log .Fatalf ("Error writing CSV record for month %s: %v" , stats .Month , err )
247+ }
248+ }
249+ writer .Flush ()
250+ if err := writer .Error (); err != nil {
251+ log .Fatalf ("Error flushing CSV writer: %v" , err )
228252 }
229253
230254 fmt .Printf ("Report generated: %s\n " , outputFile )
231255 fmt .Printf ("Total months with activity: %d\n " , len (monthlyData ))
232256}
233257
234258// extractMonth extracts YYYY-MM from date_created field with proper validation
235- func extractMonth (dateStr , currentMonth string ) string {
259+ func extractMonth (dateStr string ) string {
236260 if dateStr == "" {
237261 return ""
238262 }
239263
240264 // Handle different date formats
241265 // 2021-08-09T15:21:56.492368+0000
242266 // 2024-07-30T12:11:34Z
243-
267+
244268 var t time.Time
245269 var err error
246270
@@ -265,6 +289,7 @@ func extractMonth(dateStr, currentMonth string) string {
265289 }
266290 }
267291
292+ thisYear := time .Now ().Year ()
268293 if err != nil {
269294 // Try to extract just the date part
270295 parts := strings .Split (dateStr , "T" )
@@ -281,14 +306,14 @@ func extractMonth(dateStr, currentMonth string) string {
281306 } else {
282307 testFormat = "2006-01"
283308 }
284-
309+
285310 if testTime , testErr := time .Parse (testFormat , testDateStr ); testErr == nil {
286311 // Validate year and month ranges
287312 year := testTime .Year ()
288313 month := int (testTime .Month ())
289-
290- if year >= 2000 && year <= time . Now (). Year () &&
291- month >= 1 && month <= 12 {
314+
315+ if year >= 2000 && year <= thisYear &&
316+ month >= 1 && month <= 12 {
292317 return testTime .Format ("2006-01" )
293318 }
294319 }
@@ -302,21 +327,21 @@ func extractMonth(dateStr, currentMonth string) string {
302327 // Validate the parsed time
303328 year := t .Year ()
304329 month := int (t .Month ())
305-
330+
306331 // Check for reasonable year and month ranges
307- if year < 2000 || year > time . Now (). Year () || month < 1 || month > 12 {
332+ if year < 2000 || year > thisYear || month < 1 || month > 12 {
308333 return ""
309334 }
310335
311336 result := t .Format ("2006-01" )
312-
337+
313338 // Additional validation: don't return invalid months like 2025-26
314339 if testTime , testErr := time .Parse ("2006-01" , result ); testErr == nil {
315340 // Ensure the month is valid
316341 if testTime .Month () >= 1 && testTime .Month () <= 12 {
317342 return result
318343 }
319344 }
320-
345+
321346 return ""
322- }
347+ }
0 commit comments