Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e05b34a866 | |||
| 6526c74ed2 |
@@ -20,48 +20,14 @@ jobs:
|
|||||||
GOOS=windows GOARCH=amd64 go build -o amsterdam-windows-amd64.exe
|
GOOS=windows GOARCH=amd64 go build -o amsterdam-windows-amd64.exe
|
||||||
GOOS=darwin GOARCH=arm64 go build -o amsterdam-macos-arm64
|
GOOS=darwin GOARCH=arm64 go build -o amsterdam-macos-arm64
|
||||||
GOOS=darwin GOARCH=amd64 go build -o amsterdam-macos-amd64
|
GOOS=darwin GOARCH=amd64 go build -o amsterdam-macos-amd64
|
||||||
- name: Upload Linux AMD64 Binary
|
- name: Upload Assets to Release
|
||||||
uses: actions/upload-release-asset@v1
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
amsterdam-linux-amd64
|
||||||
|
amsterdam-linux-arm64
|
||||||
|
amsterdam-windows-amd64.exe
|
||||||
|
amsterdam-macos-arm64
|
||||||
|
amsterdam-macos-amd64
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
|
||||||
asset_path: ./amsterdam-linux-amd64
|
|
||||||
asset_name: amsterdam-linux-amd64
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Upload Linux ARM64 Binary
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
|
||||||
asset_path: ./amsterdam-linux-arm64
|
|
||||||
asset_name: amsterdam-linux-arm64
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Upload Windows Binary
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
|
||||||
asset_path: ./amsterdam-windows-amd64.exe
|
|
||||||
asset_name: amsterdam-windows-amd64.exe
|
|
||||||
asset_content_type: application/vnd.microsoft.portable-executable
|
|
||||||
- name: Upload Mac ARM64 Binary
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
|
||||||
asset_path: ./amsterdam-macos-arm64
|
|
||||||
asset_name: amsterdam-macos-arm64
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Upload Mac AMD64 Binary
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
|
||||||
asset_path: ./amsterdam-macos-amd64
|
|
||||||
asset_name: amsterdam-macos-amd64
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ import (
|
|||||||
"git.erbosoft.com/amy/amsterdam/ui"
|
"git.erbosoft.com/amy/amsterdam/ui"
|
||||||
"git.erbosoft.com/amy/amsterdam/util"
|
"git.erbosoft.com/amy/amsterdam/util"
|
||||||
"github.com/biter777/countries"
|
"github.com/biter777/countries"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ENOJOIN is an error for not being permitted to join a community.
|
// ENOJOIN is an error for not being permitted to join a community.
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ import (
|
|||||||
"git.erbosoft.com/amy/amsterdam/exports"
|
"git.erbosoft.com/amy/amsterdam/exports"
|
||||||
"git.erbosoft.com/amy/amsterdam/ui"
|
"git.erbosoft.com/amy/amsterdam/ui"
|
||||||
"git.erbosoft.com/amy/amsterdam/util"
|
"git.erbosoft.com/amy/amsterdam/util"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -26,7 +26,7 @@ import (
|
|||||||
"git.erbosoft.com/amy/amsterdam/htmlcheck"
|
"git.erbosoft.com/amy/amsterdam/htmlcheck"
|
||||||
"git.erbosoft.com/amy/amsterdam/ui"
|
"git.erbosoft.com/amy/amsterdam/ui"
|
||||||
"github.com/CloudyKit/jet/v6"
|
"github.com/CloudyKit/jet/v6"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -513,11 +513,11 @@ func ReadPosts(ctxt ui.AmContext) (string, any) {
|
|||||||
resetLastRead := false
|
resetLastRead := false
|
||||||
if ctxt.HasParameter("r") {
|
if ctxt.HasParameter("r") {
|
||||||
if err := breakRange(topic, postRange, ctxt.Parameter("r"), ","); err != nil {
|
if err := breakRange(topic, postRange, ctxt.Parameter("r"), ","); err != nil {
|
||||||
return "error", echo.NewHTTPError(http.StatusNotFound).SetInternal(err)
|
return "error", echo.NewHTTPError(http.StatusNotFound, err.Error()).Wrap(err)
|
||||||
}
|
}
|
||||||
} else if ctxt.HasParameter("rgo") {
|
} else if ctxt.HasParameter("rgo") {
|
||||||
if err := breakRange(topic, postRange, ctxt.Parameter("rgo"), "-"); err != nil {
|
if err := breakRange(topic, postRange, ctxt.Parameter("rgo"), "-"); err != nil {
|
||||||
return "error", echo.NewHTTPError(http.StatusNotFound).SetInternal(err)
|
return "error", echo.NewHTTPError(http.StatusNotFound, err.Error()).Wrap(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
postRange[0] = lastRead + 1
|
postRange[0] = lastRead + 1
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ import (
|
|||||||
"git.erbosoft.com/amy/amsterdam/database"
|
"git.erbosoft.com/amy/amsterdam/database"
|
||||||
"git.erbosoft.com/amy/amsterdam/email"
|
"git.erbosoft.com/amy/amsterdam/email"
|
||||||
"git.erbosoft.com/amy/amsterdam/ui"
|
"git.erbosoft.com/amy/amsterdam/ui"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -19,10 +19,9 @@ import (
|
|||||||
|
|
||||||
"git.erbosoft.com/amy/amsterdam/config"
|
"git.erbosoft.com/amy/amsterdam/config"
|
||||||
"git.erbosoft.com/amy/amsterdam/ui"
|
"git.erbosoft.com/amy/amsterdam/ui"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
"github.com/labstack/echo/v4/middleware"
|
"github.com/labstack/echo/v5/middleware"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/time/rate"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// EBUTTON is the standard error for an unknown button.
|
// EBUTTON is the standard error for an unknown button.
|
||||||
@@ -74,9 +73,9 @@ func AmNotFoundHandler(ctxt ui.AmContext) (string, any) {
|
|||||||
* err - The error to be handled.
|
* err - The error to be handled.
|
||||||
* c - The Echo context error is being handled on.
|
* c - The Echo context error is being handled on.
|
||||||
*/
|
*/
|
||||||
func AmErrorHandler(err error, c echo.Context) {
|
func AmErrorHandler(c *echo.Context, err error) {
|
||||||
log.Infof("-> AmErrorHandler on path %s", c.Request().URL.Path)
|
log.Infof("-> AmErrorHandler on path %s", c.Request().URL.Path)
|
||||||
if c.Response().Committed {
|
if c.Response().(*echo.Response).Committed {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cerr := ui.AmWithTempContext(c, func(ctxt ui.AmContext) (string, any) {
|
cerr := ui.AmWithTempContext(c, func(ctxt ui.AmContext) (string, any) {
|
||||||
@@ -88,14 +87,14 @@ func AmErrorHandler(err error, c echo.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// rateLimitErrorHandler is called if there's an error getting the identifier for a connection (unlikely).
|
// rateLimitErrorHandler is called if there's an error getting the identifier for a connection (unlikely).
|
||||||
func rateLimitErrorHandler(c echo.Context, err error) error {
|
func rateLimitErrorHandler(c *echo.Context, err error) error {
|
||||||
return ui.AmWithTempContext(c, func(ctxt ui.AmContext) (string, any) {
|
return ui.AmWithTempContext(c, func(ctxt ui.AmContext) (string, any) {
|
||||||
return "error", err
|
return "error", err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// rateLimitDenyHandler is called if the rate limit is exceeded by a connection.
|
// rateLimitDenyHandler is called if the rate limit is exceeded by a connection.
|
||||||
func rateLimitDenyHandler(c echo.Context, identifier string, err error) error {
|
func rateLimitDenyHandler(c *echo.Context, identifier string, err error) error {
|
||||||
return ui.AmWithTempContext(c, func(ctxt ui.AmContext) (string, any) {
|
return ui.AmWithTempContext(c, func(ctxt ui.AmContext) (string, any) {
|
||||||
ctxt.VarMap().Set("identifier", identifier)
|
ctxt.VarMap().Set("identifier", identifier)
|
||||||
return "ratelimit", err
|
return "ratelimit", err
|
||||||
@@ -105,7 +104,7 @@ func rateLimitDenyHandler(c echo.Context, identifier string, err error) error {
|
|||||||
// AmSetupRateLimiter sets up the rate-limiting middleware.
|
// AmSetupRateLimiter sets up the rate-limiting middleware.
|
||||||
func AmSetupRateLimiter() echo.MiddlewareFunc {
|
func AmSetupRateLimiter() echo.MiddlewareFunc {
|
||||||
rcfg := middleware.RateLimiterMemoryStoreConfig{
|
rcfg := middleware.RateLimiterMemoryStoreConfig{
|
||||||
Rate: rate.Limit(config.GlobalConfig.Site.RateLimit.Rate),
|
Rate: config.GlobalConfig.Site.RateLimit.Rate,
|
||||||
Burst: config.GlobalConfig.Site.RateLimit.Burst,
|
Burst: config.GlobalConfig.Site.RateLimit.Burst,
|
||||||
ExpiresIn: time.Duration(config.GlobalConfig.Site.RateLimit.ExpireMinutes) * time.Minute,
|
ExpiresIn: time.Duration(config.GlobalConfig.Site.RateLimit.ExpireMinutes) * time.Minute,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,12 @@ require (
|
|||||||
github.com/hashicorp/golang-lru v1.0.2
|
github.com/hashicorp/golang-lru v1.0.2
|
||||||
github.com/jmoiron/sqlx v1.4.0
|
github.com/jmoiron/sqlx v1.4.0
|
||||||
github.com/klauspost/lctime v0.1.0
|
github.com/klauspost/lctime v0.1.0
|
||||||
github.com/labstack/echo/v4 v4.15.1
|
github.com/labstack/echo/v5 v5.1.1
|
||||||
github.com/labstack/gommon v0.4.2
|
github.com/labstack/gommon v0.5.0
|
||||||
github.com/sirupsen/logrus v1.9.4
|
github.com/sirupsen/logrus v1.9.4
|
||||||
github.com/tkuchiki/go-timezone v0.2.3
|
github.com/tkuchiki/go-timezone v0.2.3
|
||||||
golang.org/x/net v0.52.0
|
golang.org/x/net v0.53.0
|
||||||
golang.org/x/text v0.35.0
|
golang.org/x/text v0.36.0
|
||||||
golang.org/x/time v0.15.0
|
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,10 +28,10 @@ require (
|
|||||||
github.com/CloudyKit/fastprinter v0.0.0-20251202014920-1725d2651bd4 // indirect
|
github.com/CloudyKit/fastprinter v0.0.0-20251202014920-1725d2651bd4 // indirect
|
||||||
github.com/alexflint/go-scalar v1.2.0 // indirect
|
github.com/alexflint/go-scalar v1.2.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.22 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.49.0 // indirect
|
|
||||||
golang.org/x/image v0.37.0 // indirect
|
golang.org/x/image v0.37.0 // indirect
|
||||||
golang.org/x/sys v0.42.0 // indirect
|
golang.org/x/sys v0.43.0 // indirect
|
||||||
|
golang.org/x/time v0.15.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -31,16 +31,16 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
|||||||
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||||
github.com/klauspost/lctime v0.1.0 h1:nINsuFc860M9cyYhT6vfg6U1USh7kiVBj/s/2b04U70=
|
github.com/klauspost/lctime v0.1.0 h1:nINsuFc860M9cyYhT6vfg6U1USh7kiVBj/s/2b04U70=
|
||||||
github.com/klauspost/lctime v0.1.0/go.mod h1:OwdMhr8tbQvusAsnilqkkgDQqivWlqyg0w5cfXkLiDk=
|
github.com/klauspost/lctime v0.1.0/go.mod h1:OwdMhr8tbQvusAsnilqkkgDQqivWlqyg0w5cfXkLiDk=
|
||||||
github.com/labstack/echo/v4 v4.15.1 h1:S9keusg26gZpjMmPqB5hOEvNKnmd1lNmcHrbbH2lnFs=
|
github.com/labstack/echo/v5 v5.1.1 h1:4QkvKoS8ps5ch49t8b72QS9Z581ytgxhTzxuB/CBA2I=
|
||||||
github.com/labstack/echo/v4 v4.15.1/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c=
|
github.com/labstack/echo/v5 v5.1.1/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo=
|
||||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
github.com/labstack/gommon v0.5.0 h1:6VSQ2NOzsnEJ5W6+84E0RbcaDDmgB6NIAzWCczTEe6c=
|
||||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
github.com/labstack/gommon v0.5.0/go.mod h1:Rzlg7HHy1maLfzBYGg9NZcVuz1sA68HHhLjhcEllYE0=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@@ -56,19 +56,16 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
|
|||||||
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.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
|
||||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.37.0 h1:ZiRjArKI8GwxZOoEtUfhrBtaCN+4b/7709dlT6SSnQA=
|
golang.org/x/image v0.37.0 h1:ZiRjArKI8GwxZOoEtUfhrBtaCN+4b/7709dlT6SSnQA=
|
||||||
golang.org/x/image v0.37.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=
|
golang.org/x/image v0.37.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=
|
||||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
|||||||
+62
-87
@@ -13,104 +13,90 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.erbosoft.com/amy/amsterdam/config"
|
"git.erbosoft.com/amy/amsterdam/config"
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
glog "github.com/labstack/gommon/log"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
* Gommon-log to logrus adapter
|
* slog handler that outputs to Logrus
|
||||||
*----------------------------------------------------------------------------
|
*----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* toglog converts a Logrus logging level to a glog one.
|
// slog2logrus converts slog levels to Logrus levels.
|
||||||
* Parameters:
|
var slog2logrus = map[slog.Level]log.Level{
|
||||||
* l - The Logrus log level to be converted.
|
slog.LevelDebug: log.DebugLevel,
|
||||||
* Returns:
|
slog.LevelInfo: log.InfoLevel,
|
||||||
* The equivalent glog log level.
|
slog.LevelWarn: log.WarnLevel,
|
||||||
*/
|
slog.LevelError: log.ErrorLevel,
|
||||||
func toglog(l log.Level) glog.Lvl {
|
|
||||||
switch l {
|
|
||||||
case log.DebugLevel:
|
|
||||||
return glog.DEBUG
|
|
||||||
case log.InfoLevel:
|
|
||||||
return glog.INFO
|
|
||||||
case log.WarnLevel:
|
|
||||||
return glog.WARN
|
|
||||||
case log.ErrorLevel:
|
|
||||||
return glog.ERROR
|
|
||||||
default:
|
|
||||||
return glog.OFF
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fromglog converts a glog logging level to a Logrus one.
|
// SlogLogrusHandler implements slog.Handler and routes to Logrus.
|
||||||
* Parameters:
|
type SlogLogrusHandler struct {
|
||||||
* l - The glog log level to be converted.
|
fields log.Fields // fields defined in this handler
|
||||||
* Returns:
|
groupPrefix string // group prefix
|
||||||
* The equivalent Logrus log level.
|
|
||||||
*/
|
|
||||||
func fromglog(l glog.Lvl) log.Level {
|
|
||||||
switch l {
|
|
||||||
case glog.DEBUG:
|
|
||||||
return log.DebugLevel
|
|
||||||
case glog.INFO:
|
|
||||||
return log.InfoLevel
|
|
||||||
case glog.WARN:
|
|
||||||
return log.WarnLevel
|
|
||||||
case glog.ERROR:
|
|
||||||
return log.ErrorLevel
|
|
||||||
default:
|
|
||||||
return log.PanicLevel
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EchoLogrusAdapter implements echo.Logger using logrus.
|
// NewSlogLogrusHandler creates a SlogLogrusHandler with base information.
|
||||||
type EchoLogrusAdapter struct{}
|
func NewSlogLogrusHandler() *SlogLogrusHandler {
|
||||||
|
rc := new(SlogLogrusHandler{
|
||||||
|
fields: make(log.Fields),
|
||||||
|
groupPrefix: "",
|
||||||
|
})
|
||||||
|
return rc
|
||||||
|
}
|
||||||
|
|
||||||
func (l *EchoLogrusAdapter) Output() io.Writer { return log.StandardLogger().Out }
|
// Enabled returns true if the specified log level is handled.
|
||||||
func (l *EchoLogrusAdapter) SetOutput(w io.Writer) { log.SetOutput(w) }
|
func (h *SlogLogrusHandler) Enabled(ctx context.Context, lvl slog.Level) bool {
|
||||||
func (l *EchoLogrusAdapter) Prefix() string { return "" }
|
return log.IsLevelEnabled(slog2logrus[lvl])
|
||||||
func (l *EchoLogrusAdapter) SetPrefix(p string) {}
|
}
|
||||||
func (l *EchoLogrusAdapter) Level() glog.Lvl { return toglog(log.GetLevel()) }
|
|
||||||
func (l *EchoLogrusAdapter) SetLevel(lvl glog.Lvl) { log.SetLevel(fromglog(lvl)) }
|
// Handle sends a slog.Record to the log output.
|
||||||
func (l *EchoLogrusAdapter) Print(i ...any) { log.Print(i...) }
|
func (h *SlogLogrusHandler) Handle(ctx context.Context, r slog.Record) error {
|
||||||
func (l *EchoLogrusAdapter) Printf(format string, args ...any) { log.Printf(format, args...) }
|
flds := make(log.Fields)
|
||||||
func (l *EchoLogrusAdapter) Printj(j glog.JSON) { log.WithFields(log.Fields(j)).Print() }
|
for k, v := range h.fields {
|
||||||
func (l *EchoLogrusAdapter) Debug(i ...any) { log.Debug(i...) }
|
flds[h.groupPrefix+k] = v
|
||||||
func (l *EchoLogrusAdapter) Debugf(format string, args ...any) { log.Debugf(format, args...) }
|
}
|
||||||
func (l *EchoLogrusAdapter) Debugj(j glog.JSON) { log.WithFields(log.Fields(j)).Debug() }
|
r.Attrs(func(a slog.Attr) bool {
|
||||||
func (l *EchoLogrusAdapter) Info(i ...any) { log.Info(i...) }
|
flds[h.groupPrefix+a.Key] = a.Value.Any()
|
||||||
func (l *EchoLogrusAdapter) Infof(format string, args ...any) { log.Infof(format, args...) }
|
return true
|
||||||
func (l *EchoLogrusAdapter) Infoj(j glog.JSON) { log.WithFields(log.Fields(j)).Info() }
|
})
|
||||||
func (l *EchoLogrusAdapter) Warn(i ...any) { log.Warn(i...) }
|
ntry := log.NewEntry(log.StandardLogger()).WithTime(r.Time).WithFields(flds)
|
||||||
func (l *EchoLogrusAdapter) Warnf(format string, args ...any) { log.Warnf(format, args...) }
|
ntry.Log(slog2logrus[r.Level], r.Message)
|
||||||
func (l *EchoLogrusAdapter) Warnj(j glog.JSON) { log.WithFields(log.Fields(j)).Warn() }
|
return nil
|
||||||
func (l *EchoLogrusAdapter) Error(i ...any) { log.Error(i...) }
|
}
|
||||||
func (l *EchoLogrusAdapter) Errorf(format string, args ...any) { log.Errorf(format, args...) }
|
|
||||||
func (l *EchoLogrusAdapter) Errorj(j glog.JSON) { log.WithFields(log.Fields(j)).Error() }
|
// WithAttrs creates a new Handler from this one, with extra attributes.
|
||||||
func (l *EchoLogrusAdapter) Fatal(i ...any) { log.Fatal(i...) }
|
func (h *SlogLogrusHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||||
func (l *EchoLogrusAdapter) Fatalf(format string, args ...any) { log.Fatalf(format, args...) }
|
newh := new(SlogLogrusHandler{fields: make(log.Fields)})
|
||||||
func (l *EchoLogrusAdapter) Fatalj(j glog.JSON) { log.WithFields(log.Fields(j)).Fatal() }
|
maps.Copy(newh.fields, h.fields)
|
||||||
func (l *EchoLogrusAdapter) Panic(i ...any) { log.Panic(i...) }
|
for _, a := range attrs {
|
||||||
func (l *EchoLogrusAdapter) Panicf(format string, args ...any) { log.Panicf(format, args...) }
|
newh.fields[a.Key] = a.Value.Any()
|
||||||
func (l *EchoLogrusAdapter) Panicj(j glog.JSON) { log.WithFields(log.Fields(j)).Panic() }
|
}
|
||||||
func (l *EchoLogrusAdapter) SetHeader(h string) {}
|
newh.groupPrefix = h.groupPrefix
|
||||||
|
return newh
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGroup creates a new Handler from this one, with an extra group prefix.
|
||||||
|
func (h *SlogLogrusHandler) WithGroup(name string) slog.Handler {
|
||||||
|
newh := new(SlogLogrusHandler{fields: make(log.Fields)})
|
||||||
|
maps.Copy(newh.fields, h.fields)
|
||||||
|
newh.groupPrefix = h.groupPrefix + name + "."
|
||||||
|
return newh
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
* Echo middleware adapters
|
* Echo middleware adapters
|
||||||
@@ -119,13 +105,13 @@ func (l *EchoLogrusAdapter) SetHeader(h string) {}
|
|||||||
|
|
||||||
// LogrusMiddleware installs Logrus logging into the Echo middleware chain.
|
// LogrusMiddleware installs Logrus logging into the Echo middleware chain.
|
||||||
func LogrusMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
|
func LogrusMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c *echo.Context) error {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
err := next(c)
|
err := next(c)
|
||||||
stop := time.Now()
|
stop := time.Now()
|
||||||
|
|
||||||
req := c.Request()
|
req := c.Request()
|
||||||
res := c.Response()
|
res := c.Response().(*echo.Response)
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"remote_ip": c.RealIP(),
|
"remote_ip": c.RealIP(),
|
||||||
@@ -139,17 +125,6 @@ func LogrusMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogrusPanicLogging is a log function hooked into the recovery middleware.
|
|
||||||
func LogrusPanicLogging(c echo.Context, err error, stack []byte) error {
|
|
||||||
log.Errorf("[PANIC RECOVERY] %v", err)
|
|
||||||
scanner := bufio.NewScanner(bytes.NewReader(stack))
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := strings.ReplaceAll(scanner.Text(), "\t", " ")
|
|
||||||
log.Error(line)
|
|
||||||
}
|
|
||||||
return scanner.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
* Log output file implementation
|
* Log output file implementation
|
||||||
*----------------------------------------------------------------------------
|
*----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@@ -30,8 +32,8 @@ import (
|
|||||||
"git.erbosoft.com/amy/amsterdam/htmlcheck"
|
"git.erbosoft.com/amy/amsterdam/htmlcheck"
|
||||||
"git.erbosoft.com/amy/amsterdam/ui"
|
"git.erbosoft.com/amy/amsterdam/ui"
|
||||||
"git.erbosoft.com/amy/amsterdam/util"
|
"git.erbosoft.com/amy/amsterdam/util"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
"github.com/labstack/echo/v4/middleware"
|
"github.com/labstack/echo/v5/middleware"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -41,14 +43,11 @@ var GetAndPost = []string{http.MethodGet, http.MethodPost}
|
|||||||
// setupEcho creates, configures, and returns a new Echo instance.
|
// setupEcho creates, configures, and returns a new Echo instance.
|
||||||
func setupEcho() *echo.Echo {
|
func setupEcho() *echo.Echo {
|
||||||
e := echo.New()
|
e := echo.New()
|
||||||
e.HideBanner = true
|
e.Logger = slog.New(NewSlogLogrusHandler())
|
||||||
e.Logger = &EchoLogrusAdapter{}
|
|
||||||
e.Renderer = &ui.TemplateRenderer{}
|
e.Renderer = &ui.TemplateRenderer{}
|
||||||
e.HTTPErrorHandler = AmErrorHandler
|
e.HTTPErrorHandler = AmErrorHandler
|
||||||
if !config.CommandLine.DebugPanic {
|
if !config.CommandLine.DebugPanic {
|
||||||
e.Use(middleware.RecoverWithConfig(middleware.RecoverConfig{
|
e.Use(middleware.RecoverWithConfig(middleware.DefaultRecoverConfig))
|
||||||
LogErrorFunc: LogrusPanicLogging,
|
|
||||||
}))
|
|
||||||
} else {
|
} else {
|
||||||
log.Warn("WARNING: --debug-panic in effect - DO NOT use this in production!")
|
log.Warn("WARNING: --debug-panic in effect - DO NOT use this in production!")
|
||||||
}
|
}
|
||||||
@@ -264,21 +263,24 @@ func main() {
|
|||||||
database.AmStoreAudit(database.AmNewAudit(database.AuditShutdown, 0, myIP.String()))
|
database.AmStoreAudit(database.AmNewAudit(database.AuditShutdown, 0, myIP.String()))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
sconf := echo.StartConfig{
|
||||||
|
Address: config.GlobalComputedConfig.Listen,
|
||||||
|
HideBanner: true,
|
||||||
|
HidePort: true,
|
||||||
|
GracefulTimeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
stime := time.Since(SystemStartTime)
|
stime := time.Since(SystemStartTime)
|
||||||
log.Infof("Amsterdam %s startup sequence completed in %v", config.AMSTERDAM_VERSION, stime)
|
log.Infof("Amsterdam %s startup sequence completed in %v", config.AMSTERDAM_VERSION, stime)
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
go func() {
|
go func() {
|
||||||
if err := e.Start(config.GlobalComputedConfig.Listen); err != nil && err != http.ErrServerClosed {
|
if err := sconf.Start(ctx, e); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
e.Logger.Fatalf("shutting down the server: %v", err)
|
log.Fatalf("shutting down the server: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Wait for the interrupt signal and then gracefully shut the server down.
|
// Wait for the context to be done, when the server is shut down.
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
log.Infof("Amsterdam shut down")
|
||||||
defer cancel()
|
|
||||||
if err := e.Shutdown(ctx); err != nil {
|
|
||||||
e.Logger.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import (
|
|||||||
"git.erbosoft.com/amy/amsterdam/database"
|
"git.erbosoft.com/amy/amsterdam/database"
|
||||||
"git.erbosoft.com/amy/amsterdam/ui"
|
"git.erbosoft.com/amy/amsterdam/ui"
|
||||||
"github.com/CloudyKit/jet/v6"
|
"github.com/CloudyKit/jet/v6"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -285,14 +285,14 @@ func PolicyPage(ctxt ui.AmContext) (string, any) {
|
|||||||
func JumpToShortcut(ctxt ui.AmContext) (string, any) {
|
func JumpToShortcut(ctxt ui.AmContext) (string, any) {
|
||||||
link, err := database.AmDecodePostLink(ctxt.URLParam("postlink"))
|
link, err := database.AmDecodePostLink(ctxt.URLParam("postlink"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "error", echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("not found: %s", ctxt.URLParam("postlink"))).SetInternal(err)
|
return "error", echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("not found: %s", ctxt.URLParam("postlink"))).Wrap(err)
|
||||||
}
|
}
|
||||||
scope, target := link.Classify()
|
scope, target := link.Classify()
|
||||||
if scope != "global" {
|
if scope != "global" {
|
||||||
return "error", echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("not found: %s", ctxt.URLParam("postlink")))
|
return "error", echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("not found: %s", ctxt.URLParam("postlink")))
|
||||||
}
|
}
|
||||||
if err = link.VerifyNames(ctxt.Ctx()); err != nil {
|
if err = link.VerifyNames(ctxt.Ctx()); err != nil {
|
||||||
return "error", echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("not found: %s", ctxt.URLParam("postlink"))).SetInternal(err)
|
return "error", echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("not found: %s", ctxt.URLParam("postlink"))).Wrap(err)
|
||||||
}
|
}
|
||||||
targetURL := ""
|
targetURL := ""
|
||||||
switch target {
|
switch target {
|
||||||
|
|||||||
+6
-6
@@ -27,7 +27,7 @@ import (
|
|||||||
"git.erbosoft.com/amy/amsterdam/database"
|
"git.erbosoft.com/amy/amsterdam/database"
|
||||||
"git.erbosoft.com/amy/amsterdam/util"
|
"git.erbosoft.com/amy/amsterdam/util"
|
||||||
"github.com/CloudyKit/jet/v6"
|
"github.com/CloudyKit/jet/v6"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ type AmContext interface {
|
|||||||
|
|
||||||
// amContext is the internal structure that implements AmContext.
|
// amContext is the internal structure that implements AmContext.
|
||||||
type amContext struct {
|
type amContext struct {
|
||||||
echoContext echo.Context
|
echoContext *echo.Context
|
||||||
rendervars jet.VarMap
|
rendervars jet.VarMap
|
||||||
frameTitle string
|
frameTitle string
|
||||||
frameMeta map[int]map[string]string
|
frameMeta map[int]map[string]string
|
||||||
@@ -243,7 +243,7 @@ func (c *amContext) FormFieldIsSet(name string) bool {
|
|||||||
|
|
||||||
// FormFieldValues returns all values for a specified parameter name.
|
// FormFieldValues returns all values for a specified parameter name.
|
||||||
func (c *amContext) FormFieldValues(name string) ([]string, error) {
|
func (c *amContext) FormFieldValues(name string) ([]string, error) {
|
||||||
vals, err := c.echoContext.FormParams()
|
vals, err := c.echoContext.FormValues()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return make([]string, 0), err
|
return make([]string, 0), err
|
||||||
}
|
}
|
||||||
@@ -525,7 +525,7 @@ var amContextRecycleBin chan *amContext
|
|||||||
* Internal Amsterdam context structure pointer, or nil.
|
* Internal Amsterdam context structure pointer, or nil.
|
||||||
* Standard Go error status.
|
* Standard Go error status.
|
||||||
*/
|
*/
|
||||||
func newContext(ctxt echo.Context) (*amContext, error) {
|
func newContext(ctxt *echo.Context) (*amContext, error) {
|
||||||
var rc *amContext
|
var rc *amContext
|
||||||
tmp := freeContext.Get()
|
tmp := freeContext.Get()
|
||||||
if tmp == nil {
|
if tmp == nil {
|
||||||
@@ -593,7 +593,7 @@ func newContext(ctxt echo.Context) (*amContext, error) {
|
|||||||
* Returns:
|
* Returns:
|
||||||
* The associated AmContext.
|
* The associated AmContext.
|
||||||
*/
|
*/
|
||||||
func AmContextFromEchoContext(ctxt echo.Context) AmContext {
|
func AmContextFromEchoContext(ctxt *echo.Context) AmContext {
|
||||||
myctxt := ctxt.Get("__amsterdam_context")
|
myctxt := ctxt.Get("__amsterdam_context")
|
||||||
if myctxt != nil {
|
if myctxt != nil {
|
||||||
rc, ok := myctxt.(*amContext)
|
rc, ok := myctxt.(*amContext)
|
||||||
@@ -641,7 +641,7 @@ func setupContext() func() {
|
|||||||
|
|
||||||
// ContextCreator is middleware that creates and recycles the AmContext.
|
// ContextCreator is middleware that creates and recycles the AmContext.
|
||||||
func ContextCreator(next echo.HandlerFunc) echo.HandlerFunc {
|
func ContextCreator(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c *echo.Context) error {
|
||||||
myctxt, err := newContext(c)
|
myctxt, err := newContext(c)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = next(c)
|
err = next(c)
|
||||||
|
|||||||
+2
-2
@@ -23,7 +23,7 @@ import (
|
|||||||
|
|
||||||
"git.erbosoft.com/amy/amsterdam/config"
|
"git.erbosoft.com/amy/amsterdam/config"
|
||||||
"git.erbosoft.com/amy/amsterdam/database"
|
"git.erbosoft.com/amy/amsterdam/database"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -410,7 +410,7 @@ func setupSessionManager() func() {
|
|||||||
|
|
||||||
// SessionStoreInjector is middleware that injects the session store into the context variables.
|
// SessionStoreInjector is middleware that injects the session store into the context variables.
|
||||||
func SessionStoreInjector(next echo.HandlerFunc) echo.HandlerFunc {
|
func SessionStoreInjector(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c *echo.Context) error {
|
||||||
c.Set("AmSessionStore", sessionStore)
|
c.Set("AmSessionStore", sessionStore)
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -29,7 +29,7 @@ import (
|
|||||||
|
|
||||||
"git.erbosoft.com/amy/amsterdam/database"
|
"git.erbosoft.com/amy/amsterdam/database"
|
||||||
"github.com/disintegration/imaging"
|
"github.com/disintegration/imaging"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed static_images/*
|
//go:embed static_images/*
|
||||||
@@ -64,7 +64,7 @@ func mimeTypeFromFilename(filename string) string {
|
|||||||
* Returns:
|
* Returns:
|
||||||
* Standard Go error return.
|
* Standard Go error return.
|
||||||
*/
|
*/
|
||||||
func AmServeImage(c echo.Context) error {
|
func AmServeImage(c *echo.Context) error {
|
||||||
components := strings.SplitAfter(c.Request().URL.Path, "/")
|
components := strings.SplitAfter(c.Request().URL.Path, "/")
|
||||||
var err error = nil
|
var err error = nil
|
||||||
if len(components) == 4 {
|
if len(components) == 4 {
|
||||||
@@ -105,7 +105,7 @@ func AmServeImage(c echo.Context) error {
|
|||||||
* Returns:
|
* Returns:
|
||||||
* Standard Go error return.
|
* Standard Go error return.
|
||||||
*/
|
*/
|
||||||
func AmServeVeniceCompatibleImage(c echo.Context) error {
|
func AmServeVeniceCompatibleImage(c *echo.Context) error {
|
||||||
id, err := strconv.Atoi(c.Param("id"))
|
id, err := strconv.Atoi(c.Param("id"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
var img *database.ImageStore
|
var img *database.ImageStore
|
||||||
|
|||||||
+9
-9
@@ -21,17 +21,17 @@ import (
|
|||||||
|
|
||||||
"git.erbosoft.com/amy/amsterdam/config"
|
"git.erbosoft.com/amy/amsterdam/config"
|
||||||
"git.erbosoft.com/amy/amsterdam/database"
|
"git.erbosoft.com/amy/amsterdam/database"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IPBanTest is middleware that handles the IP banning.
|
// IPBanTest is middleware that handles the IP banning.
|
||||||
func IPBanTest(next echo.HandlerFunc) echo.HandlerFunc {
|
func IPBanTest(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c *echo.Context) error {
|
||||||
// Check IP banning.
|
// Check IP banning.
|
||||||
banmsg, banerr := database.AmTestIPBan(c.Request().Context(), c.RealIP())
|
banmsg, banerr := database.AmTestIPBan(c.Request().Context(), c.RealIP())
|
||||||
if banerr != nil {
|
if banerr != nil {
|
||||||
c.Logger().Warnf("address %s could not be tested: %v", c.RealIP(), banerr)
|
log.Warnf("address %s could not be tested: %v", c.RealIP(), banerr)
|
||||||
// but let the request pass anyway
|
// but let the request pass anyway
|
||||||
} else if banmsg != "" {
|
} else if banmsg != "" {
|
||||||
amctxt := AmContextFromEchoContext(c)
|
amctxt := AmContextFromEchoContext(c)
|
||||||
@@ -43,7 +43,7 @@ func IPBanTest(next echo.HandlerFunc) echo.HandlerFunc {
|
|||||||
|
|
||||||
// CookieLoginTest is middleware that handles cookie logins.
|
// CookieLoginTest is middleware that handles cookie logins.
|
||||||
func CookieLoginTest(next echo.HandlerFunc) echo.HandlerFunc {
|
func CookieLoginTest(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c *echo.Context) error {
|
||||||
amctxt := AmContextFromEchoContext(c)
|
amctxt := AmContextFromEchoContext(c)
|
||||||
// Check for cookie login.
|
// Check for cookie login.
|
||||||
if amctxt.CurrentUser().IsAnon {
|
if amctxt.CurrentUser().IsAnon {
|
||||||
@@ -77,11 +77,11 @@ func CookieLoginTest(next echo.HandlerFunc) echo.HandlerFunc {
|
|||||||
|
|
||||||
// SetCommunity is middleware that sets the community context based on the URL.
|
// SetCommunity is middleware that sets the community context based on the URL.
|
||||||
func SetCommunity(next echo.HandlerFunc) echo.HandlerFunc {
|
func SetCommunity(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c *echo.Context) error {
|
||||||
ctxt := AmContextFromEchoContext(c)
|
ctxt := AmContextFromEchoContext(c)
|
||||||
err := ctxt.SetCommunityContext(ctxt.URLParam("cid"))
|
err := ctxt.SetCommunityContext(ctxt.URLParam("cid"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return AmSendPageData(c, ctxt, "error", echo.NewHTTPError(http.StatusNotFound).SetInternal(err))
|
return AmSendPageData(c, ctxt, "error", echo.NewHTTPError(http.StatusNotFound, err.Error()).Wrap(err))
|
||||||
}
|
}
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
b.WriteString("/comm/")
|
b.WriteString("/comm/")
|
||||||
@@ -94,7 +94,7 @@ func SetCommunity(next echo.HandlerFunc) echo.HandlerFunc {
|
|||||||
|
|
||||||
// ValidateConference is middleware that validates the user has access to the community's conference facility.
|
// ValidateConference is middleware that validates the user has access to the community's conference facility.
|
||||||
func ValidateConference(next echo.HandlerFunc) echo.HandlerFunc {
|
func ValidateConference(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c *echo.Context) error {
|
||||||
ctxt := AmContextFromEchoContext(c)
|
ctxt := AmContextFromEchoContext(c)
|
||||||
comm := ctxt.CurrentCommunity() // set by middleware
|
comm := ctxt.CurrentCommunity() // set by middleware
|
||||||
b, err := database.AmTestService(c.Request().Context(), comm, "Conference")
|
b, err := database.AmTestService(c.Request().Context(), comm, "Conference")
|
||||||
@@ -116,7 +116,7 @@ func ValidateConference(next echo.HandlerFunc) echo.HandlerFunc {
|
|||||||
|
|
||||||
// SetConference is middleware that sets the conference context based on the URL.
|
// SetConference is middleware that sets the conference context based on the URL.
|
||||||
func SetConference(next echo.HandlerFunc) echo.HandlerFunc {
|
func SetConference(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c *echo.Context) error {
|
||||||
ctxt := AmContextFromEchoContext(c)
|
ctxt := AmContextFromEchoContext(c)
|
||||||
conf, err := database.AmGetConferenceByAlias(ctxt.Ctx(), ctxt.CurrentCommunity().Id, ctxt.URLParam("confid"))
|
conf, err := database.AmGetConferenceByAlias(ctxt.Ctx(), ctxt.CurrentCommunity().Id, ctxt.URLParam("confid"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -144,7 +144,7 @@ func SetConference(next echo.HandlerFunc) echo.HandlerFunc {
|
|||||||
|
|
||||||
// SetTopic is middleware that sets the topic context based on the URL.
|
// SetTopic is middleware that sets the topic context based on the URL.
|
||||||
func SetTopic(next echo.HandlerFunc) echo.HandlerFunc {
|
func SetTopic(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c *echo.Context) error {
|
||||||
ctxt := AmContextFromEchoContext(c)
|
ctxt := AmContextFromEchoContext(c)
|
||||||
conf := ctxt.GetScratch("currentConference").(*database.Conference)
|
conf := ctxt.GetScratch("currentConference").(*database.Conference)
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -21,7 +21,7 @@ import (
|
|||||||
"git.erbosoft.com/amy/amsterdam/config"
|
"git.erbosoft.com/amy/amsterdam/config"
|
||||||
"git.erbosoft.com/amy/amsterdam/database"
|
"git.erbosoft.com/amy/amsterdam/database"
|
||||||
"github.com/klauspost/lctime"
|
"github.com/klauspost/lctime"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ import (
|
|||||||
* Returns:
|
* Returns:
|
||||||
* Standard Go error status.
|
* Standard Go error status.
|
||||||
*/
|
*/
|
||||||
func AmSendPageData(ctxt echo.Context, amctxt AmContext, command string, data any) error {
|
func AmSendPageData(ctxt *echo.Context, amctxt AmContext, command string, data any) error {
|
||||||
// Preprocess certain commands into different ones.
|
// Preprocess certain commands into different ones.
|
||||||
httprc := http.StatusOK
|
httprc := http.StatusOK
|
||||||
switch command {
|
switch command {
|
||||||
@@ -56,7 +56,7 @@ func AmSendPageData(ctxt echo.Context, amctxt AmContext, command string, data an
|
|||||||
httprc = he.Code
|
httprc = he.Code
|
||||||
m1 := he.Message
|
m1 := he.Message
|
||||||
e1 := he.Unwrap()
|
e1 := he.Unwrap()
|
||||||
if m1 == nil || m1 == "" {
|
if m1 == "" {
|
||||||
if e1 == nil {
|
if e1 == nil {
|
||||||
message = fmt.Sprintf("Unspecified error in %s", ctxt.Request().URL.String())
|
message = fmt.Sprintf("Unspecified error in %s", ctxt.Request().URL.String())
|
||||||
} else {
|
} else {
|
||||||
@@ -114,7 +114,7 @@ func AmSendPageData(ctxt echo.Context, amctxt AmContext, command string, data an
|
|||||||
err = ctxt.Render(httprc, data.(string), amctxt)
|
err = ctxt.Render(httprc, data.(string), amctxt)
|
||||||
case "framed":
|
case "framed":
|
||||||
if amctxt.FrameTitle() == "" {
|
if amctxt.FrameTitle() == "" {
|
||||||
ctxt.Logger().Errorf("*** NO FRAME TITLE set for path %s", amctxt.URLPath())
|
log.Errorf("*** NO FRAME TITLE set for path %s", amctxt.URLPath())
|
||||||
amctxt.SetFrameTitle("<<< NO FRAME TITLE >>>")
|
amctxt.SetFrameTitle("<<< NO FRAME TITLE >>>")
|
||||||
}
|
}
|
||||||
amctxt.VarMap().Set("__innerPage", data)
|
amctxt.VarMap().Set("__innerPage", data)
|
||||||
@@ -177,7 +177,7 @@ type AmPageFunc func(AmContext) (string, any)
|
|||||||
* The wrapped function.
|
* The wrapped function.
|
||||||
*/
|
*/
|
||||||
func AmWrap(myfunc AmPageFunc) echo.HandlerFunc {
|
func AmWrap(myfunc AmPageFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c *echo.Context) error {
|
||||||
ctxt := AmContextFromEchoContext(c)
|
ctxt := AmContextFromEchoContext(c)
|
||||||
|
|
||||||
// Add the dynamic headers.
|
// Add the dynamic headers.
|
||||||
@@ -191,11 +191,11 @@ func AmWrap(myfunc AmPageFunc) echo.HandlerFunc {
|
|||||||
ctxt.SetSession("lastKnownGood", ctxt.Locator())
|
ctxt.SetSession("lastKnownGood", ctxt.Locator())
|
||||||
}
|
}
|
||||||
if err := ctxt.SaveSession(); err != nil {
|
if err := ctxt.SaveSession(); err != nil {
|
||||||
c.Logger().Errorf("Session save error: %v", err)
|
log.Errorf("Session save error: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := AmSendPageData(c, ctxt, command, arg); err != nil {
|
if err := AmSendPageData(c, ctxt, command, arg); err != nil {
|
||||||
c.Logger().Errorf("Rendering error: %v", err)
|
log.Errorf("Rendering error: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -203,7 +203,7 @@ func AmWrap(myfunc AmPageFunc) echo.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AmWithTempContext runs a page function with a temporary context. Used in error handling.
|
// AmWithTempContext runs a page function with a temporary context. Used in error handling.
|
||||||
func AmWithTempContext(c echo.Context, fn AmPageFunc) error {
|
func AmWithTempContext(c *echo.Context, fn AmPageFunc) error {
|
||||||
var ctxt AmContext = nil
|
var ctxt AmContext = nil
|
||||||
myctxt := c.Get("__amsterdam_context")
|
myctxt := c.Get("__amsterdam_context")
|
||||||
if myctxt != nil {
|
if myctxt != nil {
|
||||||
@@ -233,7 +233,7 @@ func AmWithTempContext(c echo.Context, fn AmPageFunc) error {
|
|||||||
c.Response().Header().Set("Expires", expireTime)
|
c.Response().Header().Set("Expires", expireTime)
|
||||||
|
|
||||||
if err := AmSendPageData(c, ctxt, command, arg); err != nil {
|
if err := AmSendPageData(c, ctxt, command, arg); err != nil {
|
||||||
c.Logger().Errorf("Rendering error: %v", err)
|
log.Errorf("Rendering error: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.erbosoft.com/amy/amsterdam/config"
|
"git.erbosoft.com/amy/amsterdam/config"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/html"
|
"golang.org/x/net/html"
|
||||||
)
|
)
|
||||||
|
|||||||
+2
-2
@@ -31,7 +31,7 @@ import (
|
|||||||
"github.com/CloudyKit/jet/v6"
|
"github.com/CloudyKit/jet/v6"
|
||||||
"github.com/CloudyKit/jet/v6/loaders/embedfs"
|
"github.com/CloudyKit/jet/v6/loaders/embedfs"
|
||||||
"github.com/CloudyKit/jet/v6/loaders/multi"
|
"github.com/CloudyKit/jet/v6/loaders/multi"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -363,7 +363,7 @@ type TemplateRenderer struct{}
|
|||||||
* Returns:
|
* Returns:
|
||||||
* Standard Go error status.
|
* Standard Go error status.
|
||||||
*/
|
*/
|
||||||
func (r *TemplateRenderer) Render(w io.Writer, name string, data any, c echo.Context) error {
|
func (r *TemplateRenderer) Render(c *echo.Context, w io.Writer, name string, data any) error {
|
||||||
defer util.MeasureTime(fmt.Sprintf("ui.Render(%s)", name))()
|
defer util.MeasureTime(fmt.Sprintf("ui.Render(%s)", name))()
|
||||||
|
|
||||||
view, err := views.GetTemplate(name)
|
view, err := views.GetTemplate(name)
|
||||||
|
|||||||
+2
-2
@@ -26,7 +26,7 @@ import (
|
|||||||
"git.erbosoft.com/amy/amsterdam/ui"
|
"git.erbosoft.com/amy/amsterdam/ui"
|
||||||
"git.erbosoft.com/amy/amsterdam/util"
|
"git.erbosoft.com/amy/amsterdam/util"
|
||||||
"github.com/biter777/countries"
|
"github.com/biter777/countries"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v5"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -382,7 +382,7 @@ func ShowProfile(ctxt ui.AmContext) (string, any) {
|
|||||||
// Gather the info on the current user.
|
// Gather the info on the current user.
|
||||||
user, err := database.AmGetUserByName(ctxt.Ctx(), ctxt.URLParam("uname"), nil)
|
user, err := database.AmGetUserByName(ctxt.Ctx(), ctxt.URLParam("uname"), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "error", echo.NewHTTPError(http.StatusNotFound).SetInternal(err)
|
return "error", echo.NewHTTPError(http.StatusNotFound, err.Error()).Wrap(err)
|
||||||
}
|
}
|
||||||
ci, err := user.ContactInfo(ctxt.Ctx())
|
ci, err := user.ContactInfo(ctxt.Ctx())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user