From c565ec8f21bf303b597985971f14e95347436d61 Mon Sep 17 00:00:00 2001 From: "Stanislav N. aka pztrn" Date: Sat, 1 Dec 2018 03:49:04 +0500 Subject: [PATCH] Fixed timezone things with postgresql and made "Forever" work. --- .../postgresql/migrations/1_initial.go | 2 +- .../dialects/postgresql/postgresqldatabase.go | 26 +++++++++--- pastes/api_http.go | 40 +++++++++++++------ pastes/model/model.go | 12 ++++-- 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/database/dialects/postgresql/migrations/1_initial.go b/database/dialects/postgresql/migrations/1_initial.go index 594a102..51d2a2f 100644 --- a/database/dialects/postgresql/migrations/1_initial.go +++ b/database/dialects/postgresql/migrations/1_initial.go @@ -46,7 +46,7 @@ func InitialUp(tx *sql.Tx) error { COMMENT ON COLUMN pastes.data IS 'Paste data'; COMMENT ON COLUMN pastes.created_at IS 'Paste creation timestamp'; COMMENT ON COLUMN pastes.keep_for IS 'Keep for integer. 0 - forever.'; - COMMENT ON COLUMN pastes.keep_for_unit_type IS 'Keep for unit type. 1 - minutes, 2 - hours, 3 - days, 4 - months.'; + COMMENT ON COLUMN pastes.keep_for_unit_type IS 'Keep for unit type. 0 - forever, 1 - minutes, 2 - hours, 3 - days, 4 - months.'; `) if err != nil { return err diff --git a/database/dialects/postgresql/postgresqldatabase.go b/database/dialects/postgresql/postgresqldatabase.go index d6bbde8..2e2db9b 100644 --- a/database/dialects/postgresql/postgresqldatabase.go +++ b/database/dialects/postgresql/postgresqldatabase.go @@ -28,6 +28,7 @@ import ( // stdlib "database/sql" "fmt" + "time" // local "gitlab.com/pztrn/fastpastebin/database/dialects/postgresql/migrations" @@ -66,6 +67,13 @@ func (db *Database) GetPaste(pasteID int) (*pastesmodel.Paste, error) { return nil, err } + // We're aware of timezone in PostgreSQL, so SELECT will return + // timestamps in server's local timezone. We should convert them. + loc, _ := time.LoadLocation("UTC") + + utcCreatedAt := p.CreatedAt.In(loc) + p.CreatedAt = &utcCreatedAt + return p, nil } @@ -85,9 +93,15 @@ func (db *Database) GetPagedPastes(page int) ([]pastesmodel.Paste, error) { return nil, err } - for i := range pastesRaw { - if !pastesRaw[i].IsExpired() { - pastes = append(pastes, pastesRaw[i]) + // We're aware of timezone in PostgreSQL, so SELECT will return + // timestamps in server's local timezone. We should convert them. + loc, _ := time.LoadLocation("UTC") + + for _, paste := range pastesRaw { + if !paste.IsExpired() { + utcCreatedAt := paste.CreatedAt.In(loc) + paste.CreatedAt = &utcCreatedAt + pastes = append(pastes, paste) } } @@ -104,9 +118,9 @@ func (db *Database) GetPastesPages() int { } // Check if pastes isn't expired. - for i := range pastesRaw { - if !pastesRaw[i].IsExpired() { - pastes = append(pastes, pastesRaw[i]) + for _, paste := range pastesRaw { + if !paste.IsExpired() { + pastes = append(pastes, paste) } } diff --git a/pastes/api_http.go b/pastes/api_http.go index 8ae7a11..5a1f714 100644 --- a/pastes/api_http.go +++ b/pastes/api_http.go @@ -118,9 +118,14 @@ func pasteGET(ec echo.Context) error { pasteData["pasteTitle"] = paste.Title pasteData["pasteID"] = strconv.Itoa(paste.ID) pasteData["pasteDate"] = paste.CreatedAt.Format("2006-01-02 @ 15:04:05") + " UTC" - pasteData["pasteExpiration"] = paste.GetExpirationTime().Format("2006-01-02 @ 15:04:05") + " UTC" pasteData["pasteLanguage"] = paste.Language + pasteExpirationString := "Never" + if paste.KeepFor != 0 && paste.KeepForUnitType != 0 { + pasteExpirationString = paste.GetExpirationTime().Format("2006-01-02 @ 15:04:05") + " UTC" + } + pasteData["pasteExpiration"] = pasteExpirationString + if paste.Private { pasteData["pasteType"] = "Private" pasteData["pasteTs"] = strconv.FormatInt(paste.CreatedAt.Unix(), 10) + "/" @@ -264,7 +269,7 @@ func pastePOST(ec echo.Context) error { return ec.HTML(http.StatusBadRequest, errtpl) } - if !strings.ContainsAny(params["paste-keep-for"][0], "Mmhd") { + if !strings.ContainsAny(params["paste-keep-for"][0], "Mmhd") && params["paste-keep-for"][0] != "forever" { c.Logger.Debug().Msgf("'Keep paste for' field have invalid value: %s", params["paste-keep-for"][0]) errtpl := templater.GetErrorTemplate(ec, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).") return ec.HTML(http.StatusBadRequest, errtpl) @@ -288,21 +293,30 @@ func pastePOST(ec echo.Context) error { paste.CreatedAt = &createdAt // Parse "keep for" field. + // Defaulting to "forever". + keepFor := 0 + keepForUnit := 0 + if params["paste-keep-for"][0] != "forever" { + keepForUnitRegex := regexp.MustCompile("[Mmhd]") - // Get integers and strings separately. - keepForUnitRegex := regexp.MustCompile("[Mmhd]") + keepForRaw := regexInts.FindAllString(params["paste-keep-for"][0], 1)[0] + var err error + keepFor, err = strconv.Atoi(keepForRaw) + if err != nil { + if params["paste-keep-for"][0] == "forever" { + c.Logger.Debug().Msg("Keeping paste forever!") + keepFor = 0 + } else { + c.Logger.Debug().Err(err).Msg("Failed to parse 'Keep for' integer") + errtpl := templater.GetErrorTemplate(ec, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).") + return ec.HTML(http.StatusBadRequest, errtpl) + } + } - keepForRaw := regexInts.FindAllString(params["paste-keep-for"][0], 1)[0] - keepFor, err1 := strconv.Atoi(keepForRaw) - if err1 != nil { - c.Logger.Debug().Msgf("Failed to parse 'Keep for' integer: %s", err1.Error()) - errtpl := templater.GetErrorTemplate(ec, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).") - return ec.HTML(http.StatusBadRequest, errtpl) + keepForUnitRaw := keepForUnitRegex.FindAllString(params["paste-keep-for"][0], 1)[0] + keepForUnit = pastesmodel.PASTE_KEEPS_CORELLATION[keepForUnitRaw] } paste.KeepFor = keepFor - - keepForUnitRaw := keepForUnitRegex.FindAllString(params["paste-keep-for"][0], 1)[0] - keepForUnit := pastesmodel.PASTE_KEEPS_CORELLATION[keepForUnitRaw] paste.KeepForUnitType = keepForUnit // Try to autodetect if it was selected. diff --git a/pastes/model/model.go b/pastes/model/model.go index b53ed8e..7a4dbf7 100644 --- a/pastes/model/model.go +++ b/pastes/model/model.go @@ -36,6 +36,7 @@ import ( ) const ( + PASTE_KEEP_FOREVER = 0 PASTE_KEEP_FOR_MINUTES = 1 PASTE_KEEP_FOR_HOURS = 2 PASTE_KEEP_FOR_DAYS = 3 @@ -46,10 +47,11 @@ const ( var ( PASTE_KEEPS_CORELLATION = map[string]int{ - "M": PASTE_KEEP_FOR_MINUTES, - "h": PASTE_KEEP_FOR_HOURS, - "d": PASTE_KEEP_FOR_DAYS, - "m": PASTE_KEEP_FOR_MONTHS, + "M": PASTE_KEEP_FOR_MINUTES, + "h": PASTE_KEEP_FOR_HOURS, + "d": PASTE_KEEP_FOR_DAYS, + "m": PASTE_KEEP_FOR_MONTHS, + "forever": PASTE_KEEP_FOREVER, } ) @@ -99,6 +101,8 @@ func (p *Paste) GenerateCryptedCookieValue() string { func (p *Paste) GetExpirationTime() time.Time { var expirationTime time.Time switch p.KeepForUnitType { + case PASTE_KEEP_FOREVER: + expirationTime = time.Now().UTC().Add(time.Hour * 1) case PASTE_KEEP_FOR_MINUTES: expirationTime = p.CreatedAt.Add(time.Minute * time.Duration(p.KeepFor)) case PASTE_KEEP_FOR_HOURS: