From a3087047b6754244243263bedb1f9bcf0459f6c5 Mon Sep 17 00:00:00 2001 From: binwiederhier Date: Mon, 27 Feb 2023 14:34:05 -0500 Subject: [PATCH] Enhance some duration flags --- cmd/tier.go | 35 ++++++++++++++++++++++++----------- cmd/tier_test.go | 8 ++++---- util/time.go | 20 +++++++++++--------- util/time_test.go | 14 ++++++++++++++ 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/cmd/tier.go b/cmd/tier.go index 2c06e98d..c0b83d71 100644 --- a/cmd/tier.go +++ b/cmd/tier.go @@ -8,7 +8,6 @@ import ( "github.com/urfave/cli/v2" "heckel.io/ntfy/user" "heckel.io/ntfy/util" - "time" ) func init() { @@ -17,12 +16,12 @@ func init() { const ( defaultMessageLimit = 5000 - defaultMessageExpiryDuration = 12 * time.Hour + defaultMessageExpiryDuration = "12h" defaultEmailLimit = 20 defaultReservationLimit = 3 defaultAttachmentFileSizeLimit = "15M" defaultAttachmentTotalSizeLimit = "100M" - defaultAttachmentExpiryDuration = 6 * time.Hour + defaultAttachmentExpiryDuration = "6h" defaultAttachmentBandwidthLimit = "1G" ) @@ -47,12 +46,12 @@ var cmdTier = &cli.Command{ Flags: []cli.Flag{ &cli.StringFlag{Name: "name", Usage: "tier name"}, &cli.Int64Flag{Name: "message-limit", Value: defaultMessageLimit, Usage: "daily message limit"}, - &cli.DurationFlag{Name: "message-expiry-duration", Value: defaultMessageExpiryDuration, Usage: "duration after which messages are deleted"}, + &cli.StringFlag{Name: "message-expiry-duration", Value: defaultMessageExpiryDuration, Usage: "duration after which messages are deleted"}, &cli.Int64Flag{Name: "email-limit", Value: defaultEmailLimit, Usage: "daily email limit"}, &cli.Int64Flag{Name: "reservation-limit", Value: defaultReservationLimit, Usage: "topic reservation limit"}, &cli.StringFlag{Name: "attachment-file-size-limit", Value: defaultAttachmentFileSizeLimit, Usage: "per-attachment file size limit"}, &cli.StringFlag{Name: "attachment-total-size-limit", Value: defaultAttachmentTotalSizeLimit, Usage: "total size limit of attachments for the user"}, - &cli.DurationFlag{Name: "attachment-expiry-duration", Value: defaultAttachmentExpiryDuration, Usage: "duration after which attachments are deleted"}, + &cli.StringFlag{Name: "attachment-expiry-duration", Value: defaultAttachmentExpiryDuration, Usage: "duration after which attachments are deleted"}, &cli.StringFlag{Name: "attachment-bandwidth-limit", Value: defaultAttachmentBandwidthLimit, Usage: "daily bandwidth limit for attachment uploads/downloads"}, &cli.StringFlag{Name: "stripe-monthly-price-id", Usage: "Monthly Stripe price ID for paid tiers (e.g. price_12345)"}, &cli.StringFlag{Name: "stripe-yearly-price-id", Usage: "Yearly Stripe price ID for paid tiers (e.g. price_12345)"}, @@ -90,12 +89,12 @@ Examples: Flags: []cli.Flag{ &cli.StringFlag{Name: "name", Usage: "tier name"}, &cli.Int64Flag{Name: "message-limit", Usage: "daily message limit"}, - &cli.DurationFlag{Name: "message-expiry-duration", Usage: "duration after which messages are deleted"}, + &cli.StringFlag{Name: "message-expiry-duration", Usage: "duration after which messages are deleted"}, &cli.Int64Flag{Name: "email-limit", Usage: "daily email limit"}, &cli.Int64Flag{Name: "reservation-limit", Usage: "topic reservation limit"}, &cli.StringFlag{Name: "attachment-file-size-limit", Usage: "per-attachment file size limit"}, &cli.StringFlag{Name: "attachment-total-size-limit", Usage: "total size limit of attachments for the user"}, - &cli.DurationFlag{Name: "attachment-expiry-duration", Usage: "duration after which attachments are deleted"}, + &cli.StringFlag{Name: "attachment-expiry-duration", Usage: "duration after which attachments are deleted"}, &cli.StringFlag{Name: "attachment-bandwidth-limit", Usage: "daily bandwidth limit for attachment uploads/downloads"}, &cli.StringFlag{Name: "stripe-monthly-price-id", Usage: "Monthly Stripe price ID for paid tiers (e.g. price_12345)"}, &cli.StringFlag{Name: "stripe-yearly-price-id", Usage: "Yearly Stripe price ID for paid tiers (e.g. price_12345)"}, @@ -189,6 +188,10 @@ func execTierAdd(c *cli.Context) error { if name == "" { name = code } + messageExpiryDuration, err := util.ParseDuration(c.String("message-expiry-duration")) + if err != nil { + return err + } attachmentFileSizeLimit, err := util.ParseSize(c.String("attachment-file-size-limit")) if err != nil { return err @@ -201,17 +204,21 @@ func execTierAdd(c *cli.Context) error { if err != nil { return err } + attachmentExpiryDuration, err := util.ParseDuration(c.String("attachment-expiry-duration")) + if err != nil { + return err + } tier := &user.Tier{ ID: "", // Generated Code: code, Name: name, MessageLimit: c.Int64("message-limit"), - MessageExpiryDuration: c.Duration("message-expiry-duration"), + MessageExpiryDuration: messageExpiryDuration, EmailLimit: c.Int64("email-limit"), ReservationLimit: c.Int64("reservation-limit"), AttachmentFileSizeLimit: attachmentFileSizeLimit, AttachmentTotalSizeLimit: attachmentTotalSizeLimit, - AttachmentExpiryDuration: c.Duration("attachment-expiry-duration"), + AttachmentExpiryDuration: attachmentExpiryDuration, AttachmentBandwidthLimit: attachmentBandwidthLimit, StripeMonthlyPriceID: c.String("stripe-monthly-price-id"), StripeYearlyPriceID: c.String("stripe-yearly-price-id"), @@ -252,7 +259,10 @@ func execTierChange(c *cli.Context) error { tier.MessageLimit = c.Int64("message-limit") } if c.IsSet("message-expiry-duration") { - tier.MessageExpiryDuration = c.Duration("message-expiry-duration") + tier.MessageExpiryDuration, err = util.ParseDuration(c.String("message-expiry-duration")) + if err != nil { + return err + } } if c.IsSet("email-limit") { tier.EmailLimit = c.Int64("email-limit") @@ -273,7 +283,10 @@ func execTierChange(c *cli.Context) error { } } if c.IsSet("attachment-expiry-duration") { - tier.AttachmentExpiryDuration = c.Duration("attachment-expiry-duration") + tier.AttachmentExpiryDuration, err = util.ParseDuration(c.String("attachment-expiry-duration")) + if err != nil { + return err + } } if c.IsSet("attachment-bandwidth-limit") { tier.AttachmentBandwidthLimit, err = util.ParseSize(c.String("attachment-bandwidth-limit")) diff --git a/cmd/tier_test.go b/cmd/tier_test.go index a447bfbc..1774aa27 100644 --- a/cmd/tier_test.go +++ b/cmd/tier_test.go @@ -29,11 +29,11 @@ func TestCLI_Tier_AddListChangeDelete(t *testing.T) { app, _, _, stderr = newTestApp() require.Nil(t, runTierCommand(app, conf, "change", "--message-limit=999", - "--message-expiry-duration=99h", + "--message-expiry-duration=2d", "--email-limit=91", "--reservation-limit=98", "--attachment-file-size-limit=100m", - "--attachment-expiry-duration=7h", + "--attachment-expiry-duration=1d", "--attachment-total-size-limit=10G", "--attachment-bandwidth-limit=100G", "--stripe-monthly-price-id=price_991", @@ -41,11 +41,11 @@ func TestCLI_Tier_AddListChangeDelete(t *testing.T) { "pro", )) require.Contains(t, stderr.String(), "- Message limit: 999") - require.Contains(t, stderr.String(), "- Message expiry duration: 99h") + require.Contains(t, stderr.String(), "- Message expiry duration: 48h") require.Contains(t, stderr.String(), "- Email limit: 91") require.Contains(t, stderr.String(), "- Reservation limit: 98") require.Contains(t, stderr.String(), "- Attachment file size limit: 100.0 MB") - require.Contains(t, stderr.String(), "- Attachment expiry duration: 7h") + require.Contains(t, stderr.String(), "- Attachment expiry duration: 24h") require.Contains(t, stderr.String(), "- Attachment total size limit: 10.0 GB") require.Contains(t, stderr.String(), "- Stripe prices (monthly/yearly): price_991 / price_992") diff --git a/util/time.go b/util/time.go index 04d78f89..1a455770 100644 --- a/util/time.go +++ b/util/time.go @@ -45,15 +45,9 @@ func ParseFutureTime(s string, now time.Time) (time.Time, error) { return time.Time{}, errUnparsableTime } -func parseFromDuration(s string, now time.Time) (time.Time, error) { - d, err := parseDuration(s) - if err == nil { - return now.Add(d), nil - } - return time.Time{}, errUnparsableTime -} - -func parseDuration(s string) (time.Duration, error) { +// ParseDuration is like time.ParseDuration, except that it also understands days (d), which +// translates to 24 hours, e.g. "2d" or "20h". +func ParseDuration(s string) (time.Duration, error) { d, err := time.ParseDuration(s) if err == nil { return d, nil @@ -80,6 +74,14 @@ func parseDuration(s string) (time.Duration, error) { return 0, errUnparsableTime } +func parseFromDuration(s string, now time.Time) (time.Time, error) { + d, err := ParseDuration(s) + if err == nil { + return now.Add(d), nil + } + return time.Time{}, errUnparsableTime +} + func parseUnixTime(s string, now time.Time) (time.Time, error) { t, err := strconv.Atoi(s) if err != nil { diff --git a/util/time_test.go b/util/time_test.go index 557919bf..9cc343fd 100644 --- a/util/time_test.go +++ b/util/time_test.go @@ -78,3 +78,17 @@ func TestParseFutureTime_UnixTime(t *testing.T) { require.Nil(t, err) require.Equal(t, time.Date(2021, 12, 11, 0, 51, 51, 0, time.UTC), d) } + +func TestParseDuration(t *testing.T) { + d, err := ParseDuration("2d") + require.Nil(t, err) + require.Equal(t, 48*time.Hour, d) + + d, err = ParseDuration("2h") + require.Nil(t, err) + require.Equal(t, 2*time.Hour, d) + + d, err = ParseDuration("0") + require.Nil(t, err) + require.Equal(t, time.Duration(0), d) +}