Skip to content

Commit d8ae454

Browse files
author
sw33tLie
committed
add --since --until flags to db changes subcmd
1 parent ea2d28d commit d8ae454

3 files changed

Lines changed: 78 additions & 6 deletions

File tree

cmd/db.go

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,14 @@ var statsCmd = &cobra.Command{
7272
var changesCmd = &cobra.Command{
7373
Use: "changes",
7474
Short: "Show recent scope changes (default 50)",
75+
Long: `Show recent scope changes. Use --since and --until to filter by time range.
76+
77+
Supported time formats for --since and --until:
78+
today, yesterday, 7d, 30d, 90d, 1y, or YYYY-MM-DD`,
7579
RunE: func(cmd *cobra.Command, _ []string) error {
7680
limit, _ := cmd.Flags().GetInt("limit")
81+
sinceStr, _ := cmd.Flags().GetString("since")
82+
untilStr, _ := cmd.Flags().GetString("until")
7783
dbURL, err := GetDBConnectionString()
7884
if err != nil {
7985
return err
@@ -84,7 +90,21 @@ var changesCmd = &cobra.Command{
8490
return err
8591
}
8692
defer db.Close()
87-
changes, err := db.ListRecentChanges(context.Background(), limit)
93+
94+
since, err := parseTimeFlag(sinceStr)
95+
if err != nil {
96+
return fmt.Errorf("invalid --since value: %w", err)
97+
}
98+
until, err := parseTimeFlag(untilStr)
99+
if err != nil {
100+
return fmt.Errorf("invalid --until value: %w", err)
101+
}
102+
// When --until is a date, include the full day
103+
if !until.IsZero() && untilStr != "" && !strings.Contains(untilStr, "d") && untilStr != "today" && untilStr != "yesterday" {
104+
until = until.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
105+
}
106+
107+
changes, err := db.ListRecentChanges(context.Background(), limit, since, until)
88108
if err != nil {
89109
return err
90110
}
@@ -113,6 +133,37 @@ var changesCmd = &cobra.Command{
113133
},
114134
}
115135

136+
// parseTimeFlag parses a user-friendly time string into a time.Time.
137+
// Supports: today, yesterday, 7d, 30d, 90d, 1y, YYYY-MM-DD, or empty string.
138+
func parseTimeFlag(s string) (time.Time, error) {
139+
s = strings.TrimSpace(s)
140+
if s == "" {
141+
return time.Time{}, nil
142+
}
143+
now := time.Now()
144+
switch s {
145+
case "today":
146+
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()), nil
147+
case "yesterday":
148+
y := now.AddDate(0, 0, -1)
149+
return time.Date(y.Year(), y.Month(), y.Day(), 0, 0, 0, 0, y.Location()), nil
150+
case "7d":
151+
return now.AddDate(0, 0, -7), nil
152+
case "30d":
153+
return now.AddDate(0, 0, -30), nil
154+
case "90d":
155+
return now.AddDate(0, 0, -90), nil
156+
case "1y":
157+
return now.AddDate(-1, 0, 0), nil
158+
default:
159+
t, err := time.Parse("2006-01-02", s)
160+
if err != nil {
161+
return time.Time{}, fmt.Errorf("use today, yesterday, 7d, 30d, 90d, 1y, or YYYY-MM-DD")
162+
}
163+
return t, nil
164+
}
165+
}
166+
116167
var printCmd = &cobra.Command{
117168
Use: "print",
118169
Short: "Print scope data from the database",
@@ -377,6 +428,8 @@ func init() {
377428
addCmd.Flags().StringP("category", "c", "wildcard", "Category of the target")
378429
addCmd.Flags().StringP("program-url", "u", "custom", "Program URL (default: 'custom')")
379430
changesCmd.Flags().Int("limit", 50, "Number of recent changes to show")
431+
changesCmd.Flags().String("since", "", "Show changes since: today, yesterday, 7d, 30d, 90d, 1y, or YYYY-MM-DD")
432+
changesCmd.Flags().String("until", "", "Show changes until: today, yesterday, 7d, 30d, 90d, 1y, or YYYY-MM-DD")
380433
printCmd.Flags().String("platform", "all", "Comma-separated platforms (h1,bc,it,ywh,immunefi) or 'all'")
381434
printCmd.Flags().String("program", "", "Filter by program handle or full URL")
382435
printCmd.Flags().Bool("oos", false, "Include out-of-scope elements")

docs/src/library/storage.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ entries, err := db.ListEntries(ctx, storage.ListOptions{
9797
// Full-text search
9898
results, err := db.SearchTargets(ctx, "example.com")
9999

100-
// Recent changes
101-
changes, err := db.ListRecentChanges(ctx, 50)
100+
// Recent changes (limit, since, until — use zero time for no filter)
101+
changes, err := db.ListRecentChanges(ctx, 50, time.Time{}, time.Time{})
102102

103103
// Statistics
104104
stats, err := db.GetStats(ctx)

pkg/storage/storage.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,12 +1325,31 @@ func (d *DB) AddCustomTarget(ctx context.Context, target, category, programURL s
13251325

13261326
// ListRecentChanges returns the most recent N changes across all programs.
13271327
// If limit is 0, a high default is used to return all available data.
1328-
func (d *DB) ListRecentChanges(ctx context.Context, limit int) ([]Change, error) {
1328+
// since/until are optional time range filters (zero value means no filter).
1329+
func (d *DB) ListRecentChanges(ctx context.Context, limit int, since, until time.Time) ([]Change, error) {
13291330
if limit <= 0 {
13301331
limit = 1000000
13311332
}
1332-
q := "SELECT occurred_at, program_url, platform, handle, target_normalized, target_raw, target_ai_normalized, category, in_scope, is_bbp, change_type FROM scope_changes ORDER BY occurred_at DESC LIMIT $1"
1333-
rows, err := d.sql.QueryContext(ctx, q, limit)
1333+
1334+
where := "WHERE 1=1"
1335+
args := []interface{}{}
1336+
argIdx := 1
1337+
1338+
if !since.IsZero() {
1339+
where += fmt.Sprintf(" AND occurred_at >= $%d", argIdx)
1340+
args = append(args, since)
1341+
argIdx++
1342+
}
1343+
if !until.IsZero() {
1344+
where += fmt.Sprintf(" AND occurred_at <= $%d", argIdx)
1345+
args = append(args, until)
1346+
argIdx++
1347+
}
1348+
1349+
q := fmt.Sprintf("SELECT occurred_at, program_url, platform, handle, target_normalized, target_raw, target_ai_normalized, category, in_scope, is_bbp, change_type FROM scope_changes %s ORDER BY occurred_at DESC LIMIT $%d", where, argIdx)
1350+
args = append(args, limit)
1351+
1352+
rows, err := d.sql.QueryContext(ctx, q, args...)
13341353
if err != nil {
13351354
return nil, err
13361355
}

0 commit comments

Comments
 (0)