Compare commits

...

3 Commits

Author SHA1 Message Date
f8f0302564
Make linter happy and update dependencies.
Some checks failed
continuous-integration/drone/push Build is failing
2022-06-26 22:26:39 +05:00
7b6a425908
Update Drone configuration. 2022-06-26 22:10:53 +05:00
591c24bab7
Update Drone configuration. 2022-06-26 22:08:23 +05:00
31 changed files with 347 additions and 365 deletions

View File

@ -1,7 +1,7 @@
--- ---
kind: pipeline kind: pipeline
type: docker type: docker
name: build name: lint and test
steps: steps:
- name: lint - name: lint
@ -18,10 +18,30 @@ steps:
commands: commands:
- go test ./... - go test ./...
- name: docker ---
kind: pipeline
type: docker
name: build docker images
depends_on:
- "lint and test"
steps:
- name: build master image
image: plugins/docker image: plugins/docker
when: when:
branch: ["master"] branch: ["master"]
settings:
registry: code.pztrn.name
username: drone
password:
from_secret: drone_secret
repo: code.pztrn.name/pztrn/fastpastebin
auto_tag: true
- name: build tagged image
image: plugins/docker
when:
event: ["tag"] event: ["tag"]
settings: settings:
registry: code.pztrn.name registry: code.pztrn.name

View File

@ -15,6 +15,8 @@ linters:
# This linter MIGHT BE good, but who decided that I want keepFor in # This linter MIGHT BE good, but who decided that I want keepFor in
# JSON instead of keep_for for KeepFor field? # JSON instead of keep_for for KeepFor field?
- tagliatelle - tagliatelle
# Deprecated.
- exhaustivestruct
linters-settings: linters-settings:
lll: lll:
line-length: 420 line-length: 420

View File

@ -28,13 +28,13 @@ import (
"go.dev.pztrn.name/fastpastebin/internal/context" "go.dev.pztrn.name/fastpastebin/internal/context"
) )
var c *context.Context var ctx *context.Context
// New initializes pastes package and adds necessary HTTP and API // New initializes pastes package and adds necessary HTTP and API
// endpoints. // endpoints.
func New(cc *context.Context) { func New(cc *context.Context) {
c = cc ctx = cc
c.Echo.GET("/database_not_available", dbNotAvailableGet) ctx.Echo.GET("/database_not_available", dbNotAvailableGet)
c.Echo.GET("/database_not_available/raw", dbNotAvailableRawGet) ctx.Echo.GET("/database_not_available/raw", dbNotAvailableRawGet)
} }

View File

@ -28,12 +28,12 @@ import (
"go.dev.pztrn.name/fastpastebin/internal/context" "go.dev.pztrn.name/fastpastebin/internal/context"
) )
var c *context.Context var ctx *context.Context
// New initializes pastes package and adds necessary HTTP and API // New initializes pastes package and adds necessary HTTP and API
// endpoints. // endpoints.
func New(cc *context.Context) { func New(cc *context.Context) {
c = cc ctx = cc
c.Echo.GET("/", indexGet) ctx.Echo.GET("/", indexGet)
} }

View File

@ -37,8 +37,8 @@ import (
// Index of this site. // Index of this site.
func indexGet(ectx echo.Context) error { func indexGet(ectx echo.Context) error {
// We should check if database connection available. // We should check if database connection available.
dbConn := c.Database.GetDatabaseConnection() dbConn := ctx.Database.GetDatabaseConnection()
if c.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil { if ctx.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
// nolint:wrapcheck // nolint:wrapcheck
return ectx.Redirect(http.StatusFound, "/database_not_available") return ectx.Redirect(http.StatusFound, "/database_not_available")
} }

View File

@ -32,30 +32,30 @@ import (
var regexInts = regexp.MustCompile("[0-9]+") var regexInts = regexp.MustCompile("[0-9]+")
var c *context.Context var ctx *context.Context
// New initializes pastes package and adds necessary HTTP and API // New initializes pastes package and adds necessary HTTP and API
// endpoints. // endpoints.
func New(cc *context.Context) { func New(cc *context.Context) {
c = cc ctx = cc
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// HTTP endpoints. // HTTP endpoints.
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// New paste. // New paste.
c.Echo.POST("/paste/", pastePOSTWebInterface) ctx.Echo.POST("/paste/", pastePOSTWebInterface)
// Show public paste. // Show public paste.
c.Echo.GET("/paste/:id", pasteGETWebInterface) ctx.Echo.GET("/paste/:id", pasteGETWebInterface)
// Show RAW representation of public paste. // Show RAW representation of public paste.
c.Echo.GET("/paste/:id/raw", pasteRawGETWebInterface) ctx.Echo.GET("/paste/:id/raw", pasteRawGETWebInterface)
// Show private paste. // Show private paste.
c.Echo.GET("/paste/:id/:timestamp", pasteGETWebInterface) ctx.Echo.GET("/paste/:id/:timestamp", pasteGETWebInterface)
// Show RAW representation of private paste. // Show RAW representation of private paste.
c.Echo.GET("/paste/:id/:timestamp/raw", pasteRawGETWebInterface) ctx.Echo.GET("/paste/:id/:timestamp/raw", pasteRawGETWebInterface)
// Verify access to passworded paste. // Verify access to passworded paste.
c.Echo.GET("/paste/:id/:timestamp/verify", pastePasswordedVerifyGet) ctx.Echo.GET("/paste/:id/:timestamp/verify", pastePasswordedVerifyGet)
c.Echo.POST("/paste/:id/:timestamp/verify", pastePasswordedVerifyPost) ctx.Echo.POST("/paste/:id/:timestamp/verify", pastePasswordedVerifyPost)
// Pastes list. // Pastes list.
c.Echo.GET("/pastes/", pastesGET) ctx.Echo.GET("/pastes/", pastesGET)
c.Echo.GET("/pastes/:page", pastesGET) ctx.Echo.GET("/pastes/:page", pastesGET)
} }

View File

@ -31,16 +31,16 @@ const (
// value (they both will be ignored), but private will. // value (they both will be ignored), but private will.
func pasteGetData(pasteID int, timestamp int64, cookieValue string) (*structs.Paste, string) { func pasteGetData(pasteID int, timestamp int64, cookieValue string) (*structs.Paste, string) {
// Get paste. // Get paste.
paste, err1 := c.Database.GetPaste(pasteID) paste, err1 := ctx.Database.GetPaste(pasteID)
if err1 != nil { if err1 != nil {
c.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste") ctx.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste")
return nil, pasteNotFound return nil, pasteNotFound
} }
// Check if paste is expired. // Check if paste is expired.
if paste.IsExpired() { if paste.IsExpired() {
c.Logger.Error().Int("paste ID", pasteID).Msg("Paste is expired") ctx.Logger.Error().Int("paste ID", pasteID).Msg("Paste is expired")
return nil, pasteExpired return nil, pasteExpired
} }
@ -49,7 +49,7 @@ func pasteGetData(pasteID int, timestamp int64, cookieValue string) (*structs.Pa
if paste.Private { if paste.Private {
pasteTS := paste.CreatedAt.Unix() pasteTS := paste.CreatedAt.Unix()
if timestamp != pasteTS { if timestamp != pasteTS {
c.Logger.Error().Int("paste ID", pasteID).Int64("paste timestamp", pasteTS).Int64("provided timestamp", timestamp).Msg("Incorrect timestamp provided for private paste") ctx.Logger.Error().Int("paste ID", pasteID).Int64("paste timestamp", pasteTS).Int64("provided timestamp", timestamp).Msg("Incorrect timestamp provided for private paste")
return nil, pasteTimestampInvalid return nil, pasteTimestampInvalid
} }
@ -78,7 +78,7 @@ func pasteGETWebInterface(ectx echo.Context) error {
// error. // error.
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0]) pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
pasteIDStr := strconv.Itoa(pasteID) pasteIDStr := strconv.Itoa(pasteID)
c.Logger.Debug().Int("paste ID", pasteID).Msg("Trying to get paste data") ctx.Logger.Debug().Int("paste ID", pasteID).Msg("Trying to get paste data")
// Check if we have timestamp passed. // Check if we have timestamp passed.
// If passed timestamp is invalid (isn't a real UNIX timestamp) we // If passed timestamp is invalid (isn't a real UNIX timestamp) we
@ -89,7 +89,7 @@ func pasteGETWebInterface(ectx echo.Context) error {
if tsProvidedStr != "" { if tsProvidedStr != "" {
tsProvided, err := strconv.ParseInt(tsProvidedStr, 10, 64) tsProvided, err := strconv.ParseInt(tsProvidedStr, 10, 64)
if err != nil { if err != nil {
c.Logger.Error().Err(err).Int("paste ID", pasteID).Int64("provided timestamp", tsProvided).Msg("Invalid timestamp provided for getting private paste") ctx.Logger.Error().Err(err).Int("paste ID", pasteID).Int64("provided timestamp", tsProvided).Msg("Invalid timestamp provided for getting private paste")
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+pasteIDStr+" not found") errtpl := templater.GetErrorTemplate(ectx, "Paste #"+pasteIDStr+" not found")
@ -122,7 +122,7 @@ func pasteGETWebInterface(ectx echo.Context) error {
// If passed cookie value was invalid - go to paste authorization // If passed cookie value was invalid - go to paste authorization
// page. // page.
if err == pasteCookieInvalid { if err == pasteCookieInvalid {
c.Logger.Info().Int("paste ID", pasteID).Msg("Invalid cookie, redirecting to auth page") ctx.Logger.Info().Int("paste ID", pasteID).Msg("Invalid cookie, redirecting to auth page")
// nolint:wrapcheck // nolint:wrapcheck
return ectx.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDStr+"/"+ectx.Param("timestamp")+"/verify") return ectx.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDStr+"/"+ectx.Param("timestamp")+"/verify")
@ -159,7 +159,7 @@ func pasteGETWebInterface(ectx echo.Context) error {
// Tokenize paste data. // Tokenize paste data.
lexered, err3 := lexer.Tokenise(nil, paste.Data) lexered, err3 := lexer.Tokenise(nil, paste.Data)
if err3 != nil { if err3 != nil {
c.Logger.Error().Err(err3).Msg("Failed to tokenize paste data") ctx.Logger.Error().Err(err3).Msg("Failed to tokenize paste data")
} }
// Get style for HTML output. // Get style for HTML output.
style := styles.Get("monokai") style := styles.Get("monokai")
@ -174,7 +174,7 @@ func pasteGETWebInterface(ectx echo.Context) error {
err4 := formatter.Format(buf, style, lexered) err4 := formatter.Format(buf, style, lexered)
if err4 != nil { if err4 != nil {
c.Logger.Error().Err(err4).Msg("Failed to format paste data") ctx.Logger.Error().Err(err4).Msg("Failed to format paste data")
} }
pasteData["pastedata"] = buf.String() pasteData["pastedata"] = buf.String()
@ -195,9 +195,9 @@ func pastePasswordedVerifyGet(ectx echo.Context) error {
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0]) pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
// Get paste. // Get paste.
paste, err1 := c.Database.GetPaste(pasteID) paste, err1 := ctx.Database.GetPaste(pasteID)
if err1 != nil { if err1 != nil {
c.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste data") ctx.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste data")
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+pasteIDRaw+" not found") errtpl := templater.GetErrorTemplate(ectx, "Paste #"+pasteIDRaw+" not found")
@ -209,19 +209,19 @@ func pastePasswordedVerifyGet(ectx echo.Context) error {
cookie, err := ectx.Cookie("PASTE-" + strconv.Itoa(pasteID)) cookie, err := ectx.Cookie("PASTE-" + strconv.Itoa(pasteID))
if err == nil { if err == nil {
// No cookie, redirect to auth page. // No cookie, redirect to auth page.
c.Logger.Debug().Msg("Paste cookie found, checking it...") ctx.Logger.Debug().Msg("Paste cookie found, checking it...")
// Generate cookie value to check. // Generate cookie value to check.
cookieValue := paste.GenerateCryptedCookieValue() cookieValue := paste.GenerateCryptedCookieValue()
if cookieValue == cookie.Value { if cookieValue == cookie.Value {
c.Logger.Info().Msg("Valid cookie, redirecting to paste page...") ctx.Logger.Info().Msg("Valid cookie, redirecting to paste page...")
// nolint:wrapcheck // nolint:wrapcheck
return ectx.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDRaw+"/"+ectx.Param("timestamp")) return ectx.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDRaw+"/"+ectx.Param("timestamp"))
} }
c.Logger.Debug().Msg("Invalid cookie, showing auth page") ctx.Logger.Debug().Msg("Invalid cookie, showing auth page")
} }
// HTML data. // HTML data.
@ -238,9 +238,9 @@ func pastePasswordedVerifyGet(ectx echo.Context) error {
// POST for "/paste/PASTE_ID/TIMESTAMP/verify" - a password verify page. // POST for "/paste/PASTE_ID/TIMESTAMP/verify" - a password verify page.
func pastePasswordedVerifyPost(ectx echo.Context) error { func pastePasswordedVerifyPost(ectx echo.Context) error {
// We should check if database connection available. // We should check if database connection available.
dbConn := c.Database.GetDatabaseConnection() dbConn := ctx.Database.GetDatabaseConnection()
if c.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil { if ctx.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
// nolint:wrapcheck // nolint:wrapcheck
return ectx.Redirect(http.StatusFound, "/database_not_available") return ectx.Redirect(http.StatusFound, "/database_not_available")
} }
@ -250,12 +250,12 @@ func pastePasswordedVerifyPost(ectx echo.Context) error {
// We already get numbers from string, so we will not check strconv.Atoi() // We already get numbers from string, so we will not check strconv.Atoi()
// error. // error.
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0]) pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
c.Logger.Debug().Int("paste ID", pasteID).Msg("Requesting paste") ctx.Logger.Debug().Int("paste ID", pasteID).Msg("Requesting paste")
// Get paste. // Get paste.
paste, err1 := c.Database.GetPaste(pasteID) paste, err1 := ctx.Database.GetPaste(pasteID)
if err1 != nil { if err1 != nil {
c.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste") ctx.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste")
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+strconv.Itoa(pasteID)+" not found") errtpl := templater.GetErrorTemplate(ectx, "Paste #"+strconv.Itoa(pasteID)+" not found")
// nolint:wrapcheck // nolint:wrapcheck
@ -264,7 +264,7 @@ func pastePasswordedVerifyPost(ectx echo.Context) error {
params, err2 := ectx.FormParams() params, err2 := ectx.FormParams()
if err2 != nil { if err2 != nil {
c.Logger.Debug().Msg("No form parameters passed") ctx.Logger.Debug().Msg("No form parameters passed")
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+strconv.Itoa(pasteID)+" not found") errtpl := templater.GetErrorTemplate(ectx, "Paste #"+strconv.Itoa(pasteID)+" not found")
@ -295,8 +295,8 @@ func pastePasswordedVerifyPost(ectx echo.Context) error {
// Web interface version. // Web interface version.
func pasteRawGETWebInterface(ectx echo.Context) error { func pasteRawGETWebInterface(ectx echo.Context) error {
// We should check if database connection available. // We should check if database connection available.
dbConn := c.Database.GetDatabaseConnection() dbConn := ctx.Database.GetDatabaseConnection()
if c.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil { if ctx.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
// nolint:wrapcheck // nolint:wrapcheck
return ectx.Redirect(http.StatusFound, "/database_not_available/raw") return ectx.Redirect(http.StatusFound, "/database_not_available/raw")
} }
@ -305,19 +305,19 @@ func pasteRawGETWebInterface(ectx echo.Context) error {
// We already get numbers from string, so we will not check strconv.Atoi() // We already get numbers from string, so we will not check strconv.Atoi()
// error. // error.
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0]) pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
c.Logger.Debug().Int("paste ID", pasteID).Msg("Requesting paste data") ctx.Logger.Debug().Int("paste ID", pasteID).Msg("Requesting paste data")
// Get paste. // Get paste.
paste, err1 := c.Database.GetPaste(pasteID) paste, err1 := ctx.Database.GetPaste(pasteID)
if err1 != nil { if err1 != nil {
c.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste from database") ctx.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste from database")
// nolint:wrapcheck // nolint:wrapcheck
return ectx.HTML(http.StatusBadRequest, "Paste #"+pasteIDRaw+" does not exist.") return ectx.HTML(http.StatusBadRequest, "Paste #"+pasteIDRaw+" does not exist.")
} }
if paste.IsExpired() { if paste.IsExpired() {
c.Logger.Error().Int("paste ID", pasteID).Msg("Paste is expired") ctx.Logger.Error().Int("paste ID", pasteID).Msg("Paste is expired")
// nolint:wrapcheck // nolint:wrapcheck
return ectx.HTML(http.StatusBadRequest, "Paste #"+pasteIDRaw+" does not exist.") return ectx.HTML(http.StatusBadRequest, "Paste #"+pasteIDRaw+" does not exist.")
@ -329,7 +329,7 @@ func pasteRawGETWebInterface(ectx echo.Context) error {
tsProvided, err2 := strconv.ParseInt(tsProvidedStr, 10, 64) tsProvided, err2 := strconv.ParseInt(tsProvidedStr, 10, 64)
if err2 != nil { if err2 != nil {
c.Logger.Error().Err(err2).Int("paste ID", pasteID).Str("provided timestamp", tsProvidedStr).Msg("Invalid timestamp provided for getting private paste") ctx.Logger.Error().Err(err2).Int("paste ID", pasteID).Str("provided timestamp", tsProvidedStr).Msg("Invalid timestamp provided for getting private paste")
// nolint:wrapcheck // nolint:wrapcheck
return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found") return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found")
@ -337,7 +337,7 @@ func pasteRawGETWebInterface(ectx echo.Context) error {
pasteTS := paste.CreatedAt.Unix() pasteTS := paste.CreatedAt.Unix()
if tsProvided != pasteTS { if tsProvided != pasteTS {
c.Logger.Error().Int("paste ID", pasteID).Int64("provided timestamp", tsProvided).Int64("paste timestamp", pasteTS).Msg("Incorrect timestamp provided for private paste") ctx.Logger.Error().Int("paste ID", pasteID).Int64("provided timestamp", tsProvided).Int64("paste timestamp", pasteTS).Msg("Incorrect timestamp provided for private paste")
// nolint:wrapcheck // nolint:wrapcheck
return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found") return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found")
@ -348,7 +348,7 @@ func pasteRawGETWebInterface(ectx echo.Context) error {
// ToDo: figure out how to handle passworded pastes here. // ToDo: figure out how to handle passworded pastes here.
// Return error for now. // Return error for now.
if paste.Password != "" { if paste.Password != "" {
c.Logger.Error().Int("paste ID", pasteID).Msg("Cannot render paste as raw: passworded paste. Patches welcome!") ctx.Logger.Error().Int("paste ID", pasteID).Msg("Cannot render paste as raw: passworded paste. Patches welcome!")
return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found") return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found")
} }

View File

@ -22,15 +22,15 @@ const KeepPastesForever = "forever"
// requests comes from browsers via web interface. // requests comes from browsers via web interface.
func pastePOSTWebInterface(ectx echo.Context) error { func pastePOSTWebInterface(ectx echo.Context) error {
// We should check if database connection available. // We should check if database connection available.
dbConn := c.Database.GetDatabaseConnection() dbConn := ctx.Database.GetDatabaseConnection()
if c.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil { if ctx.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
// nolint:wrapcheck // nolint:wrapcheck
return ectx.Redirect(http.StatusFound, "/database_not_available") return ectx.Redirect(http.StatusFound, "/database_not_available")
} }
params, err := ectx.FormParams() params, err := ectx.FormParams()
if err != nil { if err != nil {
c.Logger.Error().Msg("Passed paste form is empty") ctx.Logger.Error().Msg("Passed paste form is empty")
errtpl := templater.GetErrorTemplate(ectx, "Cannot create empty paste") errtpl := templater.GetErrorTemplate(ectx, "Cannot create empty paste")
@ -38,11 +38,11 @@ func pastePOSTWebInterface(ectx echo.Context) error {
return ectx.HTML(http.StatusBadRequest, errtpl) return ectx.HTML(http.StatusBadRequest, errtpl)
} }
c.Logger.Debug().Msgf("Received parameters: %+v", params) ctx.Logger.Debug().Msgf("Received parameters: %+v", params)
// Do nothing if paste contents is empty. // Do nothing if paste contents is empty.
if len(params["paste-contents"][0]) == 0 { if len(params["paste-contents"][0]) == 0 {
c.Logger.Debug().Msg("Empty paste submitted, ignoring") ctx.Logger.Debug().Msg("Empty paste submitted, ignoring")
errtpl := templater.GetErrorTemplate(ectx, "Empty pastes aren't allowed.") errtpl := templater.GetErrorTemplate(ectx, "Empty pastes aren't allowed.")
@ -51,7 +51,7 @@ func pastePOSTWebInterface(ectx echo.Context) error {
} }
if !strings.ContainsAny(params["paste-keep-for"][0], "Mmhd") && params["paste-keep-for"][0] != KeepPastesForever { if !strings.ContainsAny(params["paste-keep-for"][0], "Mmhd") && params["paste-keep-for"][0] != KeepPastesForever {
c.Logger.Debug().Str("field value", params["paste-keep-for"][0]).Msg("'Keep paste for' field have invalid value") ctx.Logger.Debug().Str("field value", params["paste-keep-for"][0]).Msg("'Keep paste for' field have invalid value")
errtpl := templater.GetErrorTemplate(ectx, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).") errtpl := templater.GetErrorTemplate(ectx, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).")
@ -61,7 +61,7 @@ func pastePOSTWebInterface(ectx echo.Context) error {
// Verify captcha. // Verify captcha.
if !captcha.Verify(params["paste-captcha-id"][0], params["paste-captcha-solution"][0]) { if !captcha.Verify(params["paste-captcha-id"][0], params["paste-captcha-solution"][0]) {
c.Logger.Debug().Str("captcha ID", params["paste-captcha-id"][0]).Str("captcha solution", params["paste-captcha-solution"][0]).Msg("Invalid captcha solution") ctx.Logger.Debug().Str("captcha ID", params["paste-captcha-id"][0]).Str("captcha solution", params["paste-captcha-solution"][0]).Msg("Invalid captcha solution")
errtpl := templater.GetErrorTemplate(ectx, "Invalid captcha solution.") errtpl := templater.GetErrorTemplate(ectx, "Invalid captcha solution.")
@ -69,7 +69,7 @@ func pastePOSTWebInterface(ectx echo.Context) error {
return ectx.HTML(http.StatusBadRequest, errtpl) return ectx.HTML(http.StatusBadRequest, errtpl)
} }
// nolint:exhaustivestruct // nolint:exhaustruct
paste := &structs.Paste{ paste := &structs.Paste{
Title: params["paste-title"][0], Title: params["paste-title"][0],
Data: params["paste-contents"][0], Data: params["paste-contents"][0],
@ -95,11 +95,11 @@ func pastePOSTWebInterface(ectx echo.Context) error {
keepFor, err = strconv.Atoi(keepForRaw) keepFor, err = strconv.Atoi(keepForRaw)
if err != nil { if err != nil {
if params["paste-keep-for"][0] == KeepPastesForever { if params["paste-keep-for"][0] == KeepPastesForever {
c.Logger.Debug().Msg("Keeping paste forever!") ctx.Logger.Debug().Msg("Keeping paste forever!")
keepFor = 0 keepFor = 0
} else { } else {
c.Logger.Debug().Err(err).Msg("Failed to parse 'Keep for' integer") ctx.Logger.Debug().Err(err).Msg("Failed to parse 'Keep for' integer")
errtpl := templater.GetErrorTemplate(ectx, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).") errtpl := templater.GetErrorTemplate(ectx, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).")
@ -138,9 +138,9 @@ func pastePOSTWebInterface(ectx echo.Context) error {
_ = paste.CreatePassword(pastePassword[0]) _ = paste.CreatePassword(pastePassword[0])
} }
pasteID, err2 := c.Database.SavePaste(paste) pasteID, err2 := ctx.Database.SavePaste(paste)
if err2 != nil { if err2 != nil {
c.Logger.Error().Err(err2).Msg("Failed to save paste") ctx.Logger.Error().Err(err2).Msg("Failed to save paste")
errtpl := templater.GetErrorTemplate(ectx, "Failed to save paste. Please, try again later.") errtpl := templater.GetErrorTemplate(ectx, "Failed to save paste. Please, try again later.")
@ -149,7 +149,7 @@ func pastePOSTWebInterface(ectx echo.Context) error {
} }
newPasteIDAsString := strconv.FormatInt(pasteID, 10) newPasteIDAsString := strconv.FormatInt(pasteID, 10)
c.Logger.Debug().Msg("Paste saved, URL: /paste/" + newPasteIDAsString) ctx.Logger.Debug().Msg("Paste saved, URL: /paste/" + newPasteIDAsString)
// Private pastes have it's timestamp in URL. // Private pastes have it's timestamp in URL.
if paste.Private { if paste.Private {

View File

@ -39,8 +39,8 @@ import (
// Web interface version. // Web interface version.
func pastesGET(ectx echo.Context) error { func pastesGET(ectx echo.Context) error {
// We should check if database connection available. // We should check if database connection available.
dbConn := c.Database.GetDatabaseConnection() dbConn := ctx.Database.GetDatabaseConnection()
if c.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil { if ctx.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
// nolint:wrapcheck // nolint:wrapcheck
return ectx.Redirect(http.StatusFound, "/database_not_available") return ectx.Redirect(http.StatusFound, "/database_not_available")
} }
@ -54,17 +54,17 @@ func pastesGET(ectx echo.Context) error {
page, _ = strconv.Atoi(pageRaw) page, _ = strconv.Atoi(pageRaw)
} }
c.Logger.Debug().Int("page", page).Msg("Requested page") ctx.Logger.Debug().Int("page", page).Msg("Requested page")
// Get pastes IDs. // Get pastes IDs.
pastes, err3 := c.Database.GetPagedPastes(page) pastes, err3 := ctx.Database.GetPagedPastes(page)
c.Logger.Debug().Int("count", len(pastes)).Msg("Got pastes") ctx.Logger.Debug().Int("count", len(pastes)).Msg("Got pastes")
pastesString := "No pastes to show." pastesString := "No pastes to show."
// Show "No pastes to show" on any error for now. // Show "No pastes to show" on any error for now.
if err3 != nil { if err3 != nil {
c.Logger.Error().Err(err3).Msg("Failed to get pastes list from database") ctx.Logger.Error().Err(err3).Msg("Failed to get pastes list from database")
noPastesToShowTpl := templater.GetErrorTemplate(ectx, "No pastes to show.") noPastesToShowTpl := templater.GetErrorTemplate(ectx, "No pastes to show.")
@ -100,8 +100,8 @@ func pastesGET(ectx echo.Context) error {
} }
// Pagination. // Pagination.
pages := c.Database.GetPastesPages() pages := ctx.Database.GetPastesPages()
c.Logger.Debug().Int("total pages", pages).Int("current page", page).Msg("Paging data") ctx.Logger.Debug().Int("total pages", pages).Int("current page", page).Msg("Paging data")
paginationHTML := pagination.CreateHTML(page, pages, "/pastes/") paginationHTML := pagination.CreateHTML(page, pages, "/pastes/")
pasteListTpl := templater.GetTemplate(ectx, "pastelist_list.html", map[string]string{"pastes": pastesString, "pagination": paginationHTML}) pasteListTpl := templater.GetTemplate(ectx, "pastelist_list.html", map[string]string{"pastes": pastesString, "pagination": paginationHTML})

25
go.mod
View File

@ -3,20 +3,21 @@ module go.dev.pztrn.name/fastpastebin
go 1.16 go 1.16
require ( require (
github.com/alecthomas/chroma v0.8.2 github.com/alecthomas/chroma v0.10.0
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect github.com/go-sql-driver/mysql v1.6.0
github.com/go-sql-driver/mysql v1.5.0 github.com/jmoiron/sqlx v1.3.5
github.com/jmoiron/sqlx v1.2.0 github.com/kr/pretty v0.3.0 // indirect
github.com/labstack/echo v3.3.10+incompatible github.com/labstack/echo v3.3.10+incompatible
github.com/labstack/gommon v0.3.0 // indirect github.com/labstack/gommon v0.3.1 // indirect
github.com/lib/pq v1.9.0 github.com/lib/pq v1.10.6
github.com/pressly/goose v2.6.0+incompatible github.com/pressly/goose v2.7.0+incompatible
github.com/rs/zerolog v1.20.0 github.com/rs/zerolog v1.27.0
go.dev.pztrn.name/flagger v0.0.0-20200617193309-89bc9818b76c go.dev.pztrn.name/flagger v0.0.0-20211119225333-c010875aa337
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
golang.org/x/net v0.0.0-20201224014010-6772e930b67b golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
mvdan.cc/gofumpt v0.1.1 // indirect
) )

163
go.sum
View File

@ -1,15 +1,7 @@
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -17,118 +9,83 @@ github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f h1:q/DpyjJjZs94bziQ
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY= github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg= github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pressly/goose v2.6.0+incompatible h1:3f8zIQ8rfgP9tyI0Hmcs2YNAqUCL1c+diLe3iU8Qd/k= github.com/pressly/goose v2.7.0+incompatible h1:PWejVEv07LCerQEzMMeAtjuyCKbyprZ/LBa6K5P0OCQ=
github.com/pressly/goose v2.6.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8= github.com/pressly/goose v2.7.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8=
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo= github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.dev.pztrn.name/flagger v0.0.0-20211119225333-c010875aa337 h1:OerezdlV+T80z1tCzOQg6HSpjheU3dmxHbUbQ8NVSAs=
go.dev.pztrn.name/flagger v0.0.0-20200617193309-89bc9818b76c h1:+GgFefaTLsYDS0lXc8LNzTo6tcsA9qO3EkTAKduPAsI= go.dev.pztrn.name/flagger v0.0.0-20211119225333-c010875aa337/go.mod h1:ttPExQNCubgqqO5Y19LfIBKqmWtBocY7P9MXQEECuZo=
go.dev.pztrn.name/flagger v0.0.0-20200617193309-89bc9818b76c/go.mod h1:ttPExQNCubgqqO5Y19LfIBKqmWtBocY7P9MXQEECuZo= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0=
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c h1:dS09fXwOFF9cXBnIzZexIuUBj95U1NyQjkEhkgidDow=
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
mvdan.cc/gofumpt v0.1.1 h1:bi/1aS/5W00E2ny5q65w9SnKpWEF/UIOqDYBILpo9rA= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -32,18 +32,18 @@ import (
) )
var ( var (
c *context.Context ctx *context.Context
log zerolog.Logger log zerolog.Logger
) )
// New initializes captcha package and adds necessary HTTP and API // New initializes captcha package and adds necessary HTTP and API
// endpoints. // endpoints.
func New(cc *context.Context) { func New(cc *context.Context) {
c = cc ctx = cc
log = c.Logger.With().Str("type", "internal").Str("package", "captcha").Logger() log = ctx.Logger.With().Str("type", "internal").Str("package", "captcha").Logger()
// New paste. // New paste.
c.Echo.GET("/captcha/:id.png", echo.WrapHandler(captcha.Server(captcha.StdWidth, captcha.StdHeight))) ctx.Echo.GET("/captcha/:id.png", echo.WrapHandler(captcha.Server(captcha.StdWidth, captcha.StdHeight)))
} }
// NewCaptcha creates new captcha string. // NewCaptcha creates new captcha string.

View File

@ -100,7 +100,7 @@ func (c *Context) LoadConfiguration() {
c.Logger.Debug().Str("path", configPath).Msg("Configuration file path") c.Logger.Debug().Str("path", configPath).Msg("Configuration file path")
// nolint:exhaustivestruct // nolint:exhaustruct
c.Config = &config.Struct{} c.Config = &config.Struct{}
// Read configuration file. // Read configuration file.

View File

@ -31,6 +31,6 @@ const (
// New creates new context. // New creates new context.
func New() *Context { func New() *Context {
// nolint:exhaustivestruct // nolint:exhaustruct
return &Context{} return &Context{}
} }

View File

@ -12,44 +12,44 @@ import (
// Puts memory usage into log lines. // Puts memory usage into log lines.
func (c *Context) getMemoryUsage(event *zerolog.Event, level zerolog.Level, message string) { func (c *Context) getMemoryUsage(event *zerolog.Event, level zerolog.Level, message string) {
var m runtime.MemStats var memstats runtime.MemStats
runtime.ReadMemStats(&m) runtime.ReadMemStats(&memstats)
event.Str("memalloc", fmt.Sprintf("%dMB", m.Alloc/1024/1024)) event.Str("memalloc", fmt.Sprintf("%dMB", memstats.Alloc/1024/1024))
event.Str("memsys", fmt.Sprintf("%dMB", m.Sys/1024/1024)) event.Str("memsys", fmt.Sprintf("%dMB", memstats.Sys/1024/1024))
event.Str("numgc", fmt.Sprintf("%d", m.NumGC)) event.Str("numgc", fmt.Sprintf("%d", memstats.NumGC))
} }
// Initializes logger. // Initializes logger.
func (c *Context) initializeLogger() { func (c *Context) initializeLogger() {
// Устанавливаем форматирование логгера. // Устанавливаем форматирование логгера.
// nolint:exhaustivestruct // nolint:exhaustruct
output := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: false, TimeFormat: time.RFC3339} output := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: false, TimeFormat: time.RFC3339}
output.FormatLevel = func(lvlRaw interface{}) string { output.FormatLevel = func(lvlRaw interface{}) string {
var v string var lvl string
if lvl, ok := lvlRaw.(string); ok { if lvlAsString, ok := lvlRaw.(string); ok {
lvl = strings.ToUpper(lvl) lvlAsString = strings.ToUpper(lvlAsString)
switch lvl { switch lvlAsString {
case "DEBUG": case "DEBUG":
v = fmt.Sprintf("\x1b[30m%-5s\x1b[0m", lvl) lvl = fmt.Sprintf("\x1b[30m%-5s\x1b[0m", lvlAsString)
case "ERROR": case "ERROR":
v = fmt.Sprintf("\x1b[31m%-5s\x1b[0m", lvl) lvl = fmt.Sprintf("\x1b[31m%-5s\x1b[0m", lvlAsString)
case "FATAL": case "FATAL":
v = fmt.Sprintf("\x1b[35m%-5s\x1b[0m", lvl) lvl = fmt.Sprintf("\x1b[35m%-5s\x1b[0m", lvlAsString)
case "INFO": case "INFO":
v = fmt.Sprintf("\x1b[32m%-5s\x1b[0m", lvl) lvl = fmt.Sprintf("\x1b[32m%-5s\x1b[0m", lvlAsString)
case "PANIC": case "PANIC":
v = fmt.Sprintf("\x1b[36m%-5s\x1b[0m", lvl) lvl = fmt.Sprintf("\x1b[36m%-5s\x1b[0m", lvlAsString)
case "WARN": case "WARN":
v = fmt.Sprintf("\x1b[33m%-5s\x1b[0m", lvl) lvl = fmt.Sprintf("\x1b[33m%-5s\x1b[0m", lvlAsString)
default: default:
v = lvl lvl = lvlAsString
} }
} }
return fmt.Sprintf("| %s |", v) return fmt.Sprintf("| %s |", lvl)
} }
c.Logger = zerolog.New(output).With().Timestamp().Logger() c.Logger = zerolog.New(output).With().Timestamp().Logger()

View File

@ -46,7 +46,7 @@ type Database struct {
// a subject of change in future. // a subject of change in future.
func (db *Database) cleanup() { func (db *Database) cleanup() {
for { for {
c.Logger.Info().Msg("Starting pastes cleanup procedure...") ctx.Logger.Info().Msg("Starting pastes cleanup procedure...")
pages := db.db.GetPastesPages() pages := db.db.GetPastesPages()
@ -55,7 +55,7 @@ func (db *Database) cleanup() {
for i := 0; i < pages; i++ { for i := 0; i < pages; i++ {
pastes, err := db.db.GetPagedPastes(i) pastes, err := db.db.GetPagedPastes(i)
if err != nil { if err != nil {
c.Logger.Error().Err(err).Int("page", i).Msg("Failed to perform database cleanup") ctx.Logger.Error().Err(err).Int("page", i).Msg("Failed to perform database cleanup")
} }
for _, paste := range pastes { for _, paste := range pastes {
@ -68,11 +68,11 @@ func (db *Database) cleanup() {
for _, pasteID := range pasteIDsToRemove { for _, pasteID := range pasteIDsToRemove {
err := db.DeletePaste(pasteID) err := db.DeletePaste(pasteID)
if err != nil { if err != nil {
c.Logger.Error().Err(err).Int("paste", pasteID).Msg("Failed to delete paste!") ctx.Logger.Error().Err(err).Int("paste", pasteID).Msg("Failed to delete paste!")
} }
} }
c.Logger.Info().Msg("Pastes cleanup done.") ctx.Logger.Info().Msg("Pastes cleanup done.")
time.Sleep(time.Hour) time.Sleep(time.Hour)
} }
@ -107,16 +107,16 @@ func (db *Database) GetPastesPages() int {
// Initialize initializes connection to database. // Initialize initializes connection to database.
func (db *Database) Initialize() { func (db *Database) Initialize() {
c.Logger.Info().Msg("Initializing database connection...") ctx.Logger.Info().Msg("Initializing database connection...")
if c.Config.Database.Type == "mysql" { if ctx.Config.Database.Type == "mysql" {
mysql.New(c) mysql.New(ctx)
} else if c.Config.Database.Type == flatfiles.FlatFileDialect { } else if ctx.Config.Database.Type == flatfiles.FlatFileDialect {
flatfiles.New(c) flatfiles.New(ctx)
} else if c.Config.Database.Type == "postgresql" { } else if ctx.Config.Database.Type == "postgresql" {
postgresql.New(c) postgresql.New(ctx)
} else { } else {
c.Logger.Fatal().Str("type", c.Config.Database.Type).Msg("Unknown database type") ctx.Logger.Fatal().Str("type", ctx.Config.Database.Type).Msg("Unknown database type")
} }
go db.cleanup() go db.cleanup()

View File

@ -32,14 +32,14 @@ import (
const FlatFileDialect = "flatfiles" const FlatFileDialect = "flatfiles"
var ( var (
c *context.Context ctx *context.Context
f *FlatFiles flf *FlatFiles
) )
func New(cc *context.Context) { func New(cc *context.Context) {
c = cc ctx = cc
// nolint:exhaustivestruct // nolint:exhaustruct
f = &FlatFiles{} flf = &FlatFiles{}
c.Database.RegisterDialect(dialectinterface.Interface(Handler{})) ctx.Database.RegisterDialect(dialectinterface.Interface(Handler{}))
} }

View File

@ -49,7 +49,7 @@ func (ff *FlatFiles) DeletePaste(pasteID int) error {
// Delete from disk. // Delete from disk.
err := os.Remove(filepath.Join(ff.path, "pastes", strconv.Itoa(pasteID)+".json")) err := os.Remove(filepath.Join(ff.path, "pastes", strconv.Itoa(pasteID)+".json"))
if err != nil { if err != nil {
c.Logger.Error().Err(err).Msg("Failed to delete paste!") ctx.Logger.Error().Err(err).Msg("Failed to delete paste!")
// nolint:wrapcheck // nolint:wrapcheck
return err return err
@ -83,25 +83,25 @@ func (ff *FlatFiles) GetDatabaseConnection() *sql.DB {
func (ff *FlatFiles) GetPaste(pasteID int) (*structs.Paste, error) { func (ff *FlatFiles) GetPaste(pasteID int) (*structs.Paste, error) {
ff.writeMutex.Lock() ff.writeMutex.Lock()
pastePath := filepath.Join(ff.path, "pastes", strconv.Itoa(pasteID)+".json") pastePath := filepath.Join(ff.path, "pastes", strconv.Itoa(pasteID)+".json")
c.Logger.Debug().Str("path", pastePath).Msg("Trying to load paste data") ctx.Logger.Debug().Str("path", pastePath).Msg("Trying to load paste data")
pasteInBytes, err := ioutil.ReadFile(pastePath) pasteInBytes, err := ioutil.ReadFile(pastePath)
if err != nil { if err != nil {
c.Logger.Debug().Err(err).Msg("Failed to read paste from storage") ctx.Logger.Debug().Err(err).Msg("Failed to read paste from storage")
// nolint:wrapcheck // nolint:wrapcheck
return nil, err return nil, err
} }
c.Logger.Debug().Int("paste bytes", len(pasteInBytes)).Msg("Loaded paste") ctx.Logger.Debug().Int("paste bytes", len(pasteInBytes)).Msg("Loaded paste")
ff.writeMutex.Unlock() ff.writeMutex.Unlock()
// nolint:exhaustivestruct // nolint:exhaustruct
paste := &structs.Paste{} paste := &structs.Paste{}
err1 := json.Unmarshal(pasteInBytes, paste) err1 := json.Unmarshal(pasteInBytes, paste)
if err1 != nil { if err1 != nil {
c.Logger.Error().Err(err1).Msgf("Failed to parse paste") ctx.Logger.Error().Err(err1).Msgf("Failed to parse paste")
// nolint:wrapcheck // nolint:wrapcheck
return nil, err1 return nil, err1
@ -114,7 +114,7 @@ func (ff *FlatFiles) GetPagedPastes(page int) ([]structs.Paste, error) {
// Pagination. // Pagination.
startPagination := 0 startPagination := 0
if page > 1 { if page > 1 {
startPagination = (page - 1) * c.Config.Pastes.Pagination startPagination = (page - 1) * ctx.Config.Pastes.Pagination
} }
// Iteration one - get only public pastes. // Iteration one - get only public pastes.
@ -130,38 +130,38 @@ func (ff *FlatFiles) GetPagedPastes(page int) ([]structs.Paste, error) {
pastesData := make([]structs.Paste, 0) pastesData := make([]structs.Paste, 0)
for idx, paste := range publicPastes { for idx, paste := range publicPastes {
if len(pastesData) == c.Config.Pastes.Pagination { if len(pastesData) == ctx.Config.Pastes.Pagination {
break break
} }
if idx < startPagination { if idx < startPagination {
c.Logger.Debug().Int("paste index", idx).Msg("Paste isn't in pagination query: too low index") ctx.Logger.Debug().Int("paste index", idx).Msg("Paste isn't in pagination query: too low index")
continue continue
} }
if (idx-1 >= startPagination && page > 1 && idx > startPagination+((page-1)*c.Config.Pastes.Pagination)) || (idx-1 >= startPagination && page == 1 && idx > startPagination+(page*c.Config.Pastes.Pagination)) { if (idx-1 >= startPagination && page > 1 && idx > startPagination+((page-1)*ctx.Config.Pastes.Pagination)) || (idx-1 >= startPagination && page == 1 && idx > startPagination+(page*ctx.Config.Pastes.Pagination)) {
c.Logger.Debug().Int("paste index", idx).Msg("Paste isn't in pagination query: too high index") ctx.Logger.Debug().Int("paste index", idx).Msg("Paste isn't in pagination query: too high index")
break break
} }
c.Logger.Debug().Int("ID", paste.ID).Int("index", idx).Msg("Getting paste data") ctx.Logger.Debug().Int("ID", paste.ID).Int("index", idx).Msg("Getting paste data")
// Get paste data. // Get paste data.
// nolint:exhaustivestruct // nolint:exhaustruct
pasteData := &structs.Paste{} pasteData := &structs.Paste{}
pasteRawData, err := ioutil.ReadFile(filepath.Join(ff.path, "pastes", strconv.Itoa(paste.ID)+".json")) pasteRawData, err := ioutil.ReadFile(filepath.Join(ff.path, "pastes", strconv.Itoa(paste.ID)+".json"))
if err != nil { if err != nil {
c.Logger.Error().Err(err).Msg("Failed to read paste data") ctx.Logger.Error().Err(err).Msg("Failed to read paste data")
continue continue
} }
err1 := json.Unmarshal(pasteRawData, pasteData) err1 := json.Unmarshal(pasteRawData, pasteData)
if err1 != nil { if err1 != nil {
c.Logger.Error().Err(err1).Msg("Failed to parse paste data") ctx.Logger.Error().Err(err1).Msg("Failed to parse paste data")
continue continue
} }
@ -185,9 +185,9 @@ func (ff *FlatFiles) GetPastesPages() int {
ff.writeMutex.Unlock() ff.writeMutex.Unlock()
// Calculate pages. // Calculate pages.
pages := len(publicPastes) / c.Config.Pastes.Pagination pages := len(publicPastes) / ctx.Config.Pastes.Pagination
// Check if we have any remainder. Add 1 to pages count if so. // Check if we have any remainder. Add 1 to pages count if so.
if len(publicPastes)%c.Config.Pastes.Pagination > 0 { if len(publicPastes)%ctx.Config.Pastes.Pagination > 0 {
pages++ pages++
} }
@ -195,14 +195,14 @@ func (ff *FlatFiles) GetPastesPages() int {
} }
func (ff *FlatFiles) Initialize() { func (ff *FlatFiles) Initialize() {
c.Logger.Info().Msg("Initializing flatfiles storage...") ctx.Logger.Info().Msg("Initializing flatfiles storage...")
path := c.Config.Database.Path path := ctx.Config.Database.Path
// Get proper paste file path. // Get proper paste file path.
if strings.Contains(c.Config.Database.Path, "~") { if strings.Contains(ctx.Config.Database.Path, "~") {
curUser, err := user.Current() curUser, err := user.Current()
if err != nil { if err != nil {
c.Logger.Error().Msg("Failed to get current user. Will replace '~' for '/' in storage path!") ctx.Logger.Error().Msg("Failed to get current user. Will replace '~' for '/' in storage path!")
path = strings.Replace(path, "~", "/", -1) path = strings.Replace(path, "~", "/", -1)
} }
@ -213,40 +213,40 @@ func (ff *FlatFiles) Initialize() {
path, _ = filepath.Abs(path) path, _ = filepath.Abs(path)
ff.path = path ff.path = path
c.Logger.Debug().Msgf("Storage path is now: %s", ff.path) ctx.Logger.Debug().Msgf("Storage path is now: %s", ff.path)
// Create directory if necessary. // Create directory if necessary.
if _, err := os.Stat(ff.path); err != nil { if _, err := os.Stat(ff.path); err != nil {
c.Logger.Debug().Str("directory", ff.path).Msg("Directory does not exist, creating...") ctx.Logger.Debug().Str("directory", ff.path).Msg("Directory does not exist, creating...")
_ = os.MkdirAll(ff.path, os.ModePerm) _ = os.MkdirAll(ff.path, os.ModePerm)
} else { } else {
c.Logger.Debug().Str("directory", ff.path).Msg("Directory already exists") ctx.Logger.Debug().Str("directory", ff.path).Msg("Directory already exists")
} }
// Create directory for pastes. // Create directory for pastes.
if _, err := os.Stat(filepath.Join(ff.path, "pastes")); err != nil { if _, err := os.Stat(filepath.Join(ff.path, "pastes")); err != nil {
c.Logger.Debug().Str("directory", ff.path).Msg("Directory does not exist, creating...") ctx.Logger.Debug().Str("directory", ff.path).Msg("Directory does not exist, creating...")
_ = os.MkdirAll(filepath.Join(ff.path, "pastes"), os.ModePerm) _ = os.MkdirAll(filepath.Join(ff.path, "pastes"), os.ModePerm)
} else { } else {
c.Logger.Debug().Str("directory", ff.path).Msg("Directory already exists") ctx.Logger.Debug().Str("directory", ff.path).Msg("Directory already exists")
} }
// Load pastes index. // Load pastes index.
ff.pastesIndex = []Index{} ff.pastesIndex = []Index{}
if _, err := os.Stat(filepath.Join(ff.path, "pastes", "index.json")); err != nil { if _, err := os.Stat(filepath.Join(ff.path, "pastes", "index.json")); err != nil {
c.Logger.Warn().Msg("Pastes index file does not exist, will create new one") ctx.Logger.Warn().Msg("Pastes index file does not exist, will create new one")
} else { } else {
indexData, err := ioutil.ReadFile(filepath.Join(ff.path, "pastes", "index.json")) indexData, err := ioutil.ReadFile(filepath.Join(ff.path, "pastes", "index.json"))
if err != nil { if err != nil {
c.Logger.Fatal().Msg("Failed to read contents of index file!") ctx.Logger.Fatal().Msg("Failed to read contents of index file!")
} }
err1 := json.Unmarshal(indexData, &ff.pastesIndex) err1 := json.Unmarshal(indexData, &ff.pastesIndex)
if err1 != nil { if err1 != nil {
c.Logger.Error().Err(err1).Msg("Failed to parse index file contents from JSON into internal structure. Will create new index file. All of your previous pastes will became unavailable.") ctx.Logger.Error().Err(err1).Msg("Failed to parse index file contents from JSON into internal structure. Will create new index file. All of your previous pastes will became unavailable.")
} }
c.Logger.Debug().Int("pastes count", len(ff.pastesIndex)).Msg("Parsed pastes index") ctx.Logger.Debug().Int("pastes count", len(ff.pastesIndex)).Msg("Parsed pastes index")
} }
} }
@ -257,7 +257,7 @@ func (ff *FlatFiles) SavePaste(paste *structs.Paste) (int64, error) {
pasteID := len(filesOnDisk) + 1 pasteID := len(filesOnDisk) + 1
paste.ID = pasteID paste.ID = pasteID
c.Logger.Debug().Int("new paste ID", pasteID).Msg("Writing paste to disk") ctx.Logger.Debug().Int("new paste ID", pasteID).Msg("Writing paste to disk")
data, err := json.Marshal(paste) data, err := json.Marshal(paste)
if err != nil { if err != nil {
@ -276,7 +276,7 @@ func (ff *FlatFiles) SavePaste(paste *structs.Paste) (int64, error) {
} }
// Add it to cache. // Add it to cache.
// nolint:exhaustivestruct // nolint:exhaustruct
indexData := Index{} indexData := Index{}
indexData.ID = pasteID indexData.ID = pasteID
indexData.Private = paste.Private indexData.Private = paste.Private
@ -287,18 +287,18 @@ func (ff *FlatFiles) SavePaste(paste *structs.Paste) (int64, error) {
} }
func (ff *FlatFiles) Shutdown() { func (ff *FlatFiles) Shutdown() {
c.Logger.Info().Msg("Saving indexes...") ctx.Logger.Info().Msg("Saving indexes...")
indexData, err := json.Marshal(ff.pastesIndex) indexData, err := json.Marshal(ff.pastesIndex)
if err != nil { if err != nil {
c.Logger.Error().Err(err).Msg("Failed to encode index data into JSON") ctx.Logger.Error().Err(err).Msg("Failed to encode index data into JSON")
return return
} }
err1 := ioutil.WriteFile(filepath.Join(ff.path, "pastes", "index.json"), indexData, 0o600) err1 := ioutil.WriteFile(filepath.Join(ff.path, "pastes", "index.json"), indexData, 0o600)
if err1 != nil { if err1 != nil {
c.Logger.Error().Err(err1).Msg("Failed to write index data to file. Pretty sure that you've lost your pastes.") ctx.Logger.Error().Err(err1).Msg("Failed to write index data to file. Pretty sure that you've lost your pastes.")
return return
} }

View File

@ -33,33 +33,33 @@ import (
type Handler struct{} type Handler struct{}
func (dbh Handler) DeletePaste(pasteID int) error { func (dbh Handler) DeletePaste(pasteID int) error {
return f.DeletePaste(pasteID) return flf.DeletePaste(pasteID)
} }
func (dbh Handler) GetDatabaseConnection() *sql.DB { func (dbh Handler) GetDatabaseConnection() *sql.DB {
return f.GetDatabaseConnection() return flf.GetDatabaseConnection()
} }
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) { func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
return f.GetPaste(pasteID) return flf.GetPaste(pasteID)
} }
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) { func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
return f.GetPagedPastes(page) return flf.GetPagedPastes(page)
} }
func (dbh Handler) GetPastesPages() int { func (dbh Handler) GetPastesPages() int {
return f.GetPastesPages() return flf.GetPastesPages()
} }
func (dbh Handler) Initialize() { func (dbh Handler) Initialize() {
f.Initialize() flf.Initialize()
} }
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) { func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
return f.SavePaste(p) return flf.SavePaste(p)
} }
func (dbh Handler) Shutdown() { func (dbh Handler) Shutdown() {
f.Shutdown() flf.Shutdown()
} }

View File

@ -30,14 +30,14 @@ import (
) )
var ( var (
c *context.Context ctx *context.Context
d *Database dbAdapter *Database
) )
func New(cc *context.Context) { func New(cc *context.Context) {
c = cc ctx = cc
// nolint:exhaustivestruct // nolint:exhaustruct
d = &Database{} dbAdapter = &Database{}
c.Database.RegisterDialect(dialectinterface.Interface(Handler{})) ctx.Database.RegisterDialect(dialectinterface.Interface(Handler{}))
} }

View File

@ -33,33 +33,33 @@ import (
type Handler struct{} type Handler struct{}
func (dbh Handler) DeletePaste(pasteID int) error { func (dbh Handler) DeletePaste(pasteID int) error {
return d.DeletePaste(pasteID) return dbAdapter.DeletePaste(pasteID)
} }
func (dbh Handler) GetDatabaseConnection() *sql.DB { func (dbh Handler) GetDatabaseConnection() *sql.DB {
return d.GetDatabaseConnection() return dbAdapter.GetDatabaseConnection()
} }
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) { func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
return d.GetPaste(pasteID) return dbAdapter.GetPaste(pasteID)
} }
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) { func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
return d.GetPagedPastes(page) return dbAdapter.GetPagedPastes(page)
} }
func (dbh Handler) GetPastesPages() int { func (dbh Handler) GetPastesPages() int {
return d.GetPastesPages() return dbAdapter.GetPastesPages()
} }
func (dbh Handler) Initialize() { func (dbh Handler) Initialize() {
d.Initialize() dbAdapter.Initialize()
} }
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) { func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
return d.SavePaste(p) return dbAdapter.SavePaste(p)
} }
func (dbh Handler) Shutdown() { func (dbh Handler) Shutdown() {
d.Shutdown() dbAdapter.Shutdown()
} }

View File

@ -29,16 +29,16 @@ import (
"go.dev.pztrn.name/fastpastebin/internal/context" "go.dev.pztrn.name/fastpastebin/internal/context"
) )
var c *context.Context var ctx *context.Context
// New initializes migrations. // New initializes migrations.
func New(cc *context.Context) { func New(cc *context.Context) {
c = cc ctx = cc
} }
// Migrate launching migrations. // Migrate launching migrations.
func Migrate() { func Migrate() {
c.Logger.Info().Msg("Migrating database...") ctx.Logger.Info().Msg("Migrating database...")
_ = goose.SetDialect("mysql") _ = goose.SetDialect("mysql")
goose.AddNamedMigration("1_initial.go", InitialUp, nil) goose.AddNamedMigration("1_initial.go", InitialUp, nil)
@ -47,13 +47,13 @@ func Migrate() {
goose.AddNamedMigration("4_passworded_pastes.go", PasswordedPastesUp, PasswordedPastesDown) goose.AddNamedMigration("4_passworded_pastes.go", PasswordedPastesUp, PasswordedPastesDown)
// Add new migrations BEFORE this message. // Add new migrations BEFORE this message.
dbConn := c.Database.GetDatabaseConnection() dbConn := ctx.Database.GetDatabaseConnection()
if dbConn != nil { if dbConn != nil {
err := goose.Up(dbConn, ".") err := goose.Up(dbConn, ".")
if err != nil { if err != nil {
c.Logger.Panic().Msgf("Failed to migrate database to latest version: %s", err.Error()) ctx.Logger.Panic().Msgf("Failed to migrate database to latest version: %s", err.Error())
} }
} else { } else {
c.Logger.Warn().Msg("Current database dialect isn't supporting migrations, skipping") ctx.Logger.Warn().Msg("Current database dialect isn't supporting migrations, skipping")
} }
} }

View File

@ -80,7 +80,7 @@ func (db *Database) GetDatabaseConnection() *sql.DB {
func (db *Database) GetPaste(pasteID int) (*structs.Paste, error) { func (db *Database) GetPaste(pasteID int) (*structs.Paste, error) {
db.check() db.check()
// nolint:exhaustivestruct // nolint:exhaustruct
paste := &structs.Paste{} paste := &structs.Paste{}
err := db.db.Get(paste, db.db.Rebind("SELECT * FROM `pastes` WHERE id=?"), pasteID) err := db.db.Get(paste, db.db.Rebind("SELECT * FROM `pastes` WHERE id=?"), pasteID)
@ -103,10 +103,10 @@ func (db *Database) GetPagedPastes(page int) ([]structs.Paste, error) {
// Pagination. // Pagination.
startPagination := 0 startPagination := 0
if page > 1 { if page > 1 {
startPagination = (page - 1) * c.Config.Pastes.Pagination startPagination = (page - 1) * ctx.Config.Pastes.Pagination
} }
err := db.db.Select(&pastesRaw, db.db.Rebind("SELECT * FROM `pastes` WHERE private != true ORDER BY id DESC LIMIT ? OFFSET ?"), c.Config.Pastes.Pagination, startPagination) err := db.db.Select(&pastesRaw, db.db.Rebind("SELECT * FROM `pastes` WHERE private != true ORDER BY id DESC LIMIT ? OFFSET ?"), ctx.Config.Pastes.Pagination, startPagination)
if err != nil { if err != nil {
// nolint:wrapcheck // nolint:wrapcheck
return nil, err return nil, err
@ -142,9 +142,9 @@ func (db *Database) GetPastesPages() int {
} }
// Calculate pages. // Calculate pages.
pages := len(pastes) / c.Config.Pastes.Pagination pages := len(pastes) / ctx.Config.Pastes.Pagination
// Check if we have any remainder. Add 1 to pages count if so. // Check if we have any remainder. Add 1 to pages count if so.
if len(pastes)%c.Config.Pastes.Pagination > 0 { if len(pastes)%ctx.Config.Pastes.Pagination > 0 {
pages++ pages++
} }
@ -153,23 +153,23 @@ func (db *Database) GetPastesPages() int {
// Initialize initializes MySQL/MariaDB connection. // Initialize initializes MySQL/MariaDB connection.
func (db *Database) Initialize() { func (db *Database) Initialize() {
c.Logger.Info().Msg("Initializing database connection...") ctx.Logger.Info().Msg("Initializing database connection...")
// There might be only user, without password. MySQL/MariaDB driver // There might be only user, without password. MySQL/MariaDB driver
// in DSN wants "user" or "user:password", "user:" is invalid. // in DSN wants "user" or "user:password", "user:" is invalid.
var userpass string var userpass string
if c.Config.Database.Password == "" { if ctx.Config.Database.Password == "" {
userpass = c.Config.Database.Username userpass = ctx.Config.Database.Username
} else { } else {
userpass = c.Config.Database.Username + ":" + c.Config.Database.Password userpass = ctx.Config.Database.Username + ":" + ctx.Config.Database.Password
} }
dbConnString := fmt.Sprintf("%s@tcp(%s:%s)/%s?parseTime=true&collation=utf8mb4_unicode_ci&charset=utf8mb4", userpass, c.Config.Database.Address, c.Config.Database.Port, c.Config.Database.Database) dbConnString := fmt.Sprintf("%s@tcp(%s:%s)/%s?parseTime=true&collation=utf8mb4_unicode_ci&charset=utf8mb4", userpass, ctx.Config.Database.Address, ctx.Config.Database.Port, ctx.Config.Database.Database)
c.Logger.Debug().Str("DSN", dbConnString).Msgf("Database connection string composed") ctx.Logger.Debug().Str("DSN", dbConnString).Msgf("Database connection string composed")
dbConn, err := sqlx.Connect("mysql", dbConnString) dbConn, err := sqlx.Connect("mysql", dbConnString)
if err != nil { if err != nil {
c.Logger.Error().Err(err).Msg("Failed to connect to database") ctx.Logger.Error().Err(err).Msg("Failed to connect to database")
return return
} }
@ -177,12 +177,12 @@ func (db *Database) Initialize() {
// Force UTC for current connection. // Force UTC for current connection.
_ = dbConn.MustExec("SET @@session.time_zone='+00:00';") _ = dbConn.MustExec("SET @@session.time_zone='+00:00';")
c.Logger.Info().Msg("Database connection established") ctx.Logger.Info().Msg("Database connection established")
db.db = dbConn db.db = dbConn
// Perform migrations. // Perform migrations.
migrations.New(c) migrations.New(ctx)
migrations.Migrate() migrations.Migrate()
} }
@ -208,7 +208,7 @@ func (db *Database) Shutdown() {
if db.db != nil { if db.db != nil {
err := db.db.Close() err := db.db.Close()
if err != nil { if err != nil {
c.Logger.Error().Err(err).Msg("Failed to close database connection") ctx.Logger.Error().Err(err).Msg("Failed to close database connection")
} }
} }
} }

View File

@ -30,14 +30,14 @@ import (
) )
var ( var (
c *context.Context ctx *context.Context
d *Database dbAdapter *Database
) )
func New(cc *context.Context) { func New(cc *context.Context) {
c = cc ctx = cc
// nolint:exhaustivestruct // nolint:exhaustruct
d = &Database{} dbAdapter = &Database{}
c.Database.RegisterDialect(dialectinterface.Interface(Handler{})) ctx.Database.RegisterDialect(dialectinterface.Interface(Handler{}))
} }

View File

@ -33,33 +33,33 @@ import (
type Handler struct{} type Handler struct{}
func (dbh Handler) DeletePaste(pasteID int) error { func (dbh Handler) DeletePaste(pasteID int) error {
return d.DeletePaste(pasteID) return dbAdapter.DeletePaste(pasteID)
} }
func (dbh Handler) GetDatabaseConnection() *sql.DB { func (dbh Handler) GetDatabaseConnection() *sql.DB {
return d.GetDatabaseConnection() return dbAdapter.GetDatabaseConnection()
} }
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) { func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
return d.GetPaste(pasteID) return dbAdapter.GetPaste(pasteID)
} }
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) { func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
return d.GetPagedPastes(page) return dbAdapter.GetPagedPastes(page)
} }
func (dbh Handler) GetPastesPages() int { func (dbh Handler) GetPastesPages() int {
return d.GetPastesPages() return dbAdapter.GetPastesPages()
} }
func (dbh Handler) Initialize() { func (dbh Handler) Initialize() {
d.Initialize() dbAdapter.Initialize()
} }
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) { func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
return d.SavePaste(p) return dbAdapter.SavePaste(p)
} }
func (dbh Handler) Shutdown() { func (dbh Handler) Shutdown() {
d.Shutdown() dbAdapter.Shutdown()
} }

View File

@ -29,16 +29,16 @@ import (
"go.dev.pztrn.name/fastpastebin/internal/context" "go.dev.pztrn.name/fastpastebin/internal/context"
) )
var c *context.Context var ctx *context.Context
// New initializes migrations. // New initializes migrations.
func New(cc *context.Context) { func New(cc *context.Context) {
c = cc ctx = cc
} }
// Migrate launching migrations. // Migrate launching migrations.
func Migrate() { func Migrate() {
c.Logger.Info().Msg("Migrating database...") ctx.Logger.Info().Msg("Migrating database...")
_ = goose.SetDialect("postgres") _ = goose.SetDialect("postgres")
goose.AddNamedMigration("1_initial.go", InitialUp, nil) goose.AddNamedMigration("1_initial.go", InitialUp, nil)
@ -47,14 +47,14 @@ func Migrate() {
goose.AddNamedMigration("4_passworded_pastes.go", PasswordedPastesUp, PasswordedPastesDown) goose.AddNamedMigration("4_passworded_pastes.go", PasswordedPastesUp, PasswordedPastesDown)
// Add new migrations BEFORE this message. // Add new migrations BEFORE this message.
dbConn := c.Database.GetDatabaseConnection() dbConn := ctx.Database.GetDatabaseConnection()
if dbConn != nil { if dbConn != nil {
err := goose.Up(dbConn, ".") err := goose.Up(dbConn, ".")
if err != nil { if err != nil {
c.Logger.Info().Msgf("%+v", err) ctx.Logger.Info().Msgf("%+v", err)
c.Logger.Panic().Msgf("Failed to migrate database to latest version: %s", err.Error()) ctx.Logger.Panic().Msgf("Failed to migrate database to latest version: %s", err.Error())
} }
} else { } else {
c.Logger.Warn().Msg("Current database dialect isn't supporting migrations, skipping") ctx.Logger.Warn().Msg("Current database dialect isn't supporting migrations, skipping")
} }
} }

View File

@ -28,6 +28,7 @@ package postgresql
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"net"
"time" "time"
// PostgreSQL driver. // PostgreSQL driver.
@ -83,7 +84,7 @@ func (db *Database) GetDatabaseConnection() *sql.DB {
func (db *Database) GetPaste(pasteID int) (*structs.Paste, error) { func (db *Database) GetPaste(pasteID int) (*structs.Paste, error) {
db.check() db.check()
// nolint:exhaustivestruct // nolint:exhaustruct
paste := &structs.Paste{} paste := &structs.Paste{}
err := db.db.Get(paste, db.db.Rebind("SELECT * FROM pastes WHERE id=$1"), pasteID) err := db.db.Get(paste, db.db.Rebind("SELECT * FROM pastes WHERE id=$1"), pasteID)
@ -113,10 +114,10 @@ func (db *Database) GetPagedPastes(page int) ([]structs.Paste, error) {
// Pagination. // Pagination.
startPagination := 0 startPagination := 0
if page > 1 { if page > 1 {
startPagination = (page - 1) * c.Config.Pastes.Pagination startPagination = (page - 1) * ctx.Config.Pastes.Pagination
} }
err := db.db.Select(&pastesRaw, db.db.Rebind("SELECT * FROM pastes WHERE private != true ORDER BY id DESC LIMIT $1 OFFSET $2"), c.Config.Pastes.Pagination, startPagination) err := db.db.Select(&pastesRaw, db.db.Rebind("SELECT * FROM pastes WHERE private != true ORDER BY id DESC LIMIT $1 OFFSET $2"), ctx.Config.Pastes.Pagination, startPagination)
if err != nil { if err != nil {
// nolint:wrapcheck // nolint:wrapcheck
return nil, err return nil, err
@ -158,9 +159,9 @@ func (db *Database) GetPastesPages() int {
} }
// Calculate pages. // Calculate pages.
pages := len(pastes) / c.Config.Pastes.Pagination pages := len(pastes) / ctx.Config.Pastes.Pagination
// Check if we have any remainder. Add 1 to pages count if so. // Check if we have any remainder. Add 1 to pages count if so.
if len(pastes)%c.Config.Pastes.Pagination > 0 { if len(pastes)%ctx.Config.Pastes.Pagination > 0 {
pages++ pages++
} }
@ -169,31 +170,31 @@ func (db *Database) GetPastesPages() int {
// Initialize initializes MySQL/MariaDB connection. // Initialize initializes MySQL/MariaDB connection.
func (db *Database) Initialize() { func (db *Database) Initialize() {
c.Logger.Info().Msg("Initializing database connection...") ctx.Logger.Info().Msg("Initializing database connection...")
var userpass string var userpass string
if c.Config.Database.Password == "" { if ctx.Config.Database.Password == "" {
userpass = c.Config.Database.Username userpass = ctx.Config.Database.Username
} else { } else {
userpass = c.Config.Database.Username + ":" + c.Config.Database.Password userpass = ctx.Config.Database.Username + ":" + ctx.Config.Database.Password
} }
dbConnString := fmt.Sprintf("postgres://%s@%s:%s/%s?connect_timeout=10&fallback_application_name=fastpastebin&sslmode=disable", userpass, c.Config.Database.Address, c.Config.Database.Port, c.Config.Database.Database) dbConnString := fmt.Sprintf("postgres://%s@%s/%s?connect_timeout=10&fallback_application_name=fastpastebin&sslmode=disable", userpass, net.JoinHostPort(ctx.Config.Database.Address, ctx.Config.Database.Port), ctx.Config.Database.Database)
c.Logger.Debug().Str("DSN", dbConnString).Msg("Database connection string composed") ctx.Logger.Debug().Str("DSN", dbConnString).Msg("Database connection string composed")
dbConn, err := sqlx.Connect("postgres", dbConnString) dbConn, err := sqlx.Connect("postgres", dbConnString)
if err != nil { if err != nil {
c.Logger.Error().Err(err).Msg("Failed to connect to database") ctx.Logger.Error().Err(err).Msg("Failed to connect to database")
return return
} }
c.Logger.Info().Msg("Database connection established") ctx.Logger.Info().Msg("Database connection established")
db.db = dbConn db.db = dbConn
// Perform migrations. // Perform migrations.
migrations.New(c) migrations.New(ctx)
migrations.Migrate() migrations.Migrate()
} }
@ -206,22 +207,22 @@ func (db *Database) SavePaste(paste *structs.Paste) (int64, error) {
return 0, err return 0, err
} }
var id int64 var newPasteID int64
err = stmt.Get(&id, paste) err = stmt.Get(&newPasteID, paste)
if err != nil { if err != nil {
// nolint:wrapcheck // nolint:wrapcheck
return 0, err return 0, err
} }
return id, nil return newPasteID, nil
} }
func (db *Database) Shutdown() { func (db *Database) Shutdown() {
if db.db != nil { if db.db != nil {
err := db.db.Close() err := db.db.Close()
if err != nil { if err != nil {
c.Logger.Error().Err(err).Msg("Failed to close database connection") ctx.Logger.Error().Err(err).Msg("Failed to close database connection")
} }
} }
} }

View File

@ -30,15 +30,15 @@ import (
) )
var ( var (
c *context.Context ctx *context.Context
d *Database dbAdapter *Database
) )
// New initializes database structure. // New initializes database structure.
func New(cc *context.Context) { func New(cc *context.Context) {
c = cc ctx = cc
// nolint:exhaustivestruct // nolint:exhaustruct
d = &Database{} dbAdapter = &Database{}
c.RegisterDatabaseInterface(databaseinterface.Interface(Handler{})) ctx.RegisterDatabaseInterface(databaseinterface.Interface(Handler{}))
} }

View File

@ -36,38 +36,38 @@ import (
type Handler struct{} type Handler struct{}
func (dbh Handler) DeletePaste(pasteID int) error { func (dbh Handler) DeletePaste(pasteID int) error {
return d.DeletePaste(pasteID) return dbAdapter.DeletePaste(pasteID)
} }
func (dbh Handler) GetDatabaseConnection() *sql.DB { func (dbh Handler) GetDatabaseConnection() *sql.DB {
return d.GetDatabaseConnection() return dbAdapter.GetDatabaseConnection()
} }
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) { func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
return d.GetPaste(pasteID) return dbAdapter.GetPaste(pasteID)
} }
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) { func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
return d.GetPagedPastes(page) return dbAdapter.GetPagedPastes(page)
} }
func (dbh Handler) GetPastesPages() int { func (dbh Handler) GetPastesPages() int {
return d.GetPastesPages() return dbAdapter.GetPastesPages()
} }
// Initialize initializes connection to database. // Initialize initializes connection to database.
func (dbh Handler) Initialize() { func (dbh Handler) Initialize() {
d.Initialize() dbAdapter.Initialize()
} }
func (dbh Handler) RegisterDialect(di dialectinterface.Interface) { func (dbh Handler) RegisterDialect(di dialectinterface.Interface) {
d.RegisterDialect(di) dbAdapter.RegisterDialect(di)
} }
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) { func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
return d.SavePaste(p) return dbAdapter.SavePaste(p)
} }
func (dbh Handler) Shutdown() { func (dbh Handler) Shutdown() {
d.Shutdown() dbAdapter.Shutdown()
} }

View File

@ -42,6 +42,7 @@ func CreateHTML(currentPage int, pages int, linksBase string) string {
var ( var (
ellipsisStartAdded = false ellipsisStartAdded = false
ellipsisEndAdded = false ellipsisEndAdded = false
// nolint:varnamelen
i = 2 i = 2
) )

View File

@ -35,7 +35,7 @@ import (
) )
var ( var (
c *context.Context ctx *context.Context
log zerolog.Logger log zerolog.Logger
) )
@ -123,6 +123,6 @@ func GetTemplate(ectx echo.Context, name string, data map[string]string) string
// Initialize initializes package. // Initialize initializes package.
func Initialize(cc *context.Context) { func Initialize(cc *context.Context) {
c = cc ctx = cc
log = c.Logger.With().Str("type", "internal").Str("package", "templater").Logger() log = ctx.Logger.With().Str("type", "internal").Str("package", "templater").Logger()
} }