From b2a701c87a1334b624c9bcf5a31acc342088097a Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Thu, 3 Oct 2024 14:10:45 +0200 Subject: [PATCH 01/10] Automatically resize images and save them as webp --- cmd/backend/config.go | 66 +++++++++------ cmd/backend/images.go | 38 +++++++++ cmd/frontend/articles.go | 25 +----- cmd/frontend/issues.go | 24 +----- go.mod | 71 +++++++++-------- go.sum | 168 ++++++++++++++++++--------------------- 6 files changed, 200 insertions(+), 192 deletions(-) create mode 100644 cmd/backend/images.go diff --git a/cmd/backend/config.go b/cmd/backend/config.go index 2f8f8e3..9d41706 100644 --- a/cmd/backend/config.go +++ b/cmd/backend/config.go @@ -12,36 +12,40 @@ import ( ) type Config struct { - ArticleDir string - ConfigFile string - DBName string - Description string - Domain string - FirebaseKey string - KeyFile string - Link string - LogFile string - PDFDir string - PicsDir string - Port string - RSSFile string - Title string - WebDir string + ArticleDir string + ConfigFile string + DBName string + Description string + Domain string + FirebaseKey string + KeyFile string + Link string + LogFile string + PDFDir string + PicsDir string + Port string + RSSFile string + Title string + WebDir string + MaxImgHeight int + MaxImgWidth int } func newConfig() *Config { return &Config{ - ArticleDir: "/var/www/cpolis/articles", - ConfigFile: "/etc/cpolis/config.toml", - DBName: "cpolis", - FirebaseKey: "/var/www/cpolis/serviceAccountKey.json", - KeyFile: "/var/www/cpolis/cpolis.key", - LogFile: "/var/log/cpolis.log", - PDFDir: "/var/www/cpolis/pdfs", - PicsDir: "/var/www/cpolis/pics", - Port: ":8080", - RSSFile: "/var/www/cpolis/cpolis.rss", - WebDir: "/var/www/cpolis/web", + ArticleDir: "/var/www/cpolis/articles", + ConfigFile: "/etc/cpolis/config.toml", + DBName: "cpolis", + FirebaseKey: "/var/www/cpolis/serviceAccountKey.json", + KeyFile: "/var/www/cpolis/cpolis.key", + LogFile: "/var/log/cpolis.log", + MaxImgHeight: 1080, + MaxImgWidth: 1920, + PDFDir: "/var/www/cpolis/pdfs", + PicsDir: "/var/www/cpolis/pics", + Port: ":8080", + RSSFile: "/var/www/cpolis/cpolis.rss", + WebDir: "/var/www/cpolis/web", } } @@ -110,6 +114,8 @@ func (c *Config) handleCliArgs() error { flag.StringVar(&c.RSSFile, "rss", c.RSSFile, "RSS file") flag.StringVar(&c.Title, "title", c.Title, "channel title") flag.StringVar(&c.WebDir, "web", c.WebDir, "web directory") + flag.IntVar(&c.MaxImgHeight, "height", c.MaxImgHeight, "maximum image height") + flag.IntVar(&c.MaxImgWidth, "width", c.MaxImgWidth, "maximum image width") flag.IntVar(&port, "port", port, "port") flag.Parse() @@ -186,6 +192,14 @@ func (c *Config) setupConfig(cliConfig *Config) error { return fmt.Errorf("error setting up file: %v", err) } + if cliConfig.MaxImgHeight != defaultConfig.MaxImgHeight { + c.MaxImgHeight = cliConfig.MaxImgHeight + } + + if cliConfig.MaxImgWidth != defaultConfig.MaxImgWidth { + c.MaxImgWidth = cliConfig.MaxImgWidth + } + if cliConfig.PDFDir != defaultConfig.PDFDir { c.PDFDir = cliConfig.PDFDir } diff --git a/cmd/backend/images.go b/cmd/backend/images.go new file mode 100644 index 0000000..367ed3a --- /dev/null +++ b/cmd/backend/images.go @@ -0,0 +1,38 @@ +package backend + +import ( + "fmt" + "io" + "os" + + "github.com/chai2010/webp" + "github.com/disintegration/imaging" + "github.com/google/uuid" +) + +func SaveImage(c *Config, src io.Reader) (string, error) { + img, err := imaging.Decode(src, imaging.AutoOrientation(true)) + if err != nil { + return "", fmt.Errorf("error decoding image: %v", err) + } + + if img.Bounds().Dy() > c.MaxImgHeight { + img = imaging.Resize(img, 0, c.MaxImgHeight, imaging.Lanczos) + } + if img.Bounds().Dx() > c.MaxImgWidth { + img = imaging.Resize(img, c.MaxImgWidth, 0, imaging.Lanczos) + } + + filename := fmt.Sprint(c.PicsDir, "/", uuid.New(), ".webp") + file, err := os.Create(filename) + if err != nil { + return "", fmt.Errorf("error creating new image file: %v", err) + } + defer file.Close() + + if err = webp.Encode(file, img, &webp.Options{Lossless: true}); err != nil { + return "", fmt.Errorf("error encoding image as webp: %v", err) + } + + return filename, nil +} diff --git a/cmd/frontend/articles.go b/cmd/frontend/articles.go index befb441..65a2993 100644 --- a/cmd/frontend/articles.go +++ b/cmd/frontend/articles.go @@ -4,16 +4,12 @@ import ( "encoding/json" "fmt" "html/template" - "io" "log" "net/http" "os" - "path/filepath" "strconv" - "strings" "time" - "github.com/google/uuid" b "streifling.com/jason/cpolis/cmd/backend" ) @@ -448,7 +444,7 @@ func UploadArticleImage(c *b.Config, s *b.CookieStore) http.HandlerFunc { return } - file, header, err := r.FormFile("article-image") + file, _, err := r.FormFile("article-image") if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusBadRequest) @@ -456,30 +452,13 @@ func UploadArticleImage(c *b.Config, s *b.CookieStore) http.HandlerFunc { } defer file.Close() - nameStrings := strings.Split(header.Filename, ".") - extension := "." + nameStrings[len(nameStrings)-1] - filename := fmt.Sprint(uuid.New(), extension) - absFilepath, err := filepath.Abs(fmt.Sprint(c.PicsDir, "/", filename)) + filename, err := b.SaveImage(c, file) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } - img, err := os.Create(absFilepath) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - defer img.Close() - - if _, err = io.Copy(img, file); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - url := fmt.Sprint(c.Domain, "/image/serve/", filename) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(url) diff --git a/cmd/frontend/issues.go b/cmd/frontend/issues.go index a17b625..58aaf5b 100644 --- a/cmd/frontend/issues.go +++ b/cmd/frontend/issues.go @@ -3,16 +3,13 @@ package frontend import ( "fmt" "html/template" - "io" "log" "mime" "net/http" "os" "path/filepath" - "strings" "time" - "github.com/google/uuid" b "streifling.com/jason/cpolis/cmd/backend" ) @@ -152,7 +149,7 @@ func UploadIssueImage(c *b.Config, s *b.CookieStore) http.HandlerFunc { return } - file, header, err := r.FormFile("issue-image") + file, _, err := r.FormFile("issue-image") if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -160,30 +157,13 @@ func UploadIssueImage(c *b.Config, s *b.CookieStore) http.HandlerFunc { } defer file.Close() - nameStrings := strings.Split(header.Filename, ".") - extension := "." + nameStrings[len(nameStrings)-1] - filename := fmt.Sprint(uuid.New(), extension) - absFilepath, err := filepath.Abs(fmt.Sprint(c.PicsDir, "/", filename)) + filename, err := b.SaveImage(c, file) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } - img, err := os.Create(absFilepath) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - defer img.Close() - - if _, err = io.Copy(img, file); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - session.Values["issue-image"] = filename if err = session.Save(r, w); err != nil { log.Println(err) diff --git a/go.mod b/go.mod index c4f0419..4339332 100644 --- a/go.mod +++ b/go.mod @@ -1,59 +1,66 @@ module streifling.com/jason/cpolis -go 1.22.0 +go 1.22.6 + +toolchain go1.23.1 require ( firebase.google.com/go/v4 v4.14.1 git.streifling.com/jason/rss v0.1.3 github.com/BurntSushi/toml v1.3.2 + github.com/anthonynsimon/bild v0.14.0 + github.com/chai2010/webp v1.1.1 + github.com/disintegration/imaging v1.6.2 github.com/go-sql-driver/mysql v1.7.1 github.com/google/uuid v1.6.0 github.com/gorilla/sessions v1.2.2 github.com/microcosm-cc/bluemonday v1.0.26 - github.com/yuin/goldmark v1.7.0 - golang.org/x/crypto v0.21.0 - golang.org/x/term v0.18.0 - google.golang.org/api v0.170.0 + github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd + github.com/yuin/goldmark v1.7.4 + golang.org/x/crypto v0.27.0 + golang.org/x/term v0.24.0 + google.golang.org/api v0.191.0 ) require ( - cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/compute v1.24.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/firestore v1.15.0 // indirect - cloud.google.com/go/iam v1.1.7 // indirect - cloud.google.com/go/longrunning v0.5.5 // indirect - cloud.google.com/go/storage v1.40.0 // indirect + cloud.google.com/go v0.115.0 // indirect + cloud.google.com/go/auth v0.8.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect + cloud.google.com/go/firestore v1.16.0 // indirect + cloud.google.com/go/iam v1.1.13 // indirect + cloud.google.com/go/longrunning v0.5.11 // indirect + cloud.google.com/go/storage v1.43.0 // indirect github.com/MicahParks/keyfunc v1.9.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/s2a-go v0.1.7 // indirect + github.com/google/s2a-go v0.1.8 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/googleapis/gax-go/v2 v2.13.0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/securecookie v1.1.2 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.5.0 // indirect - google.golang.org/appengine v1.6.8 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + golang.org/x/image v0.18.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/time v0.6.0 // indirect google.golang.org/appengine/v2 v2.0.2 // indirect - google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2 // indirect - google.golang.org/grpc v1.62.1 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/go.sum b/go.sum index 2ded0a3..f8445ec 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,20 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= -cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= -cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8= -cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk= -cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= -cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= -cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= -cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= -cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= -cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g= +cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= +cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= +cloud.google.com/go/auth v0.8.1 h1:QZW9FjC5lZzN864p13YxvAtGUlQ+KgRL+8Sg45Z6vxo= +cloud.google.com/go/auth v0.8.1/go.mod h1:qGVp/Y3kDRSDZ5gFD/XPUfYQ9xW1iI7q8RIRoCyBbJc= +cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/firestore v1.16.0 h1:YwmDHcyrxVRErWcgxunzEaZxtNbc8QoFYA/JOEwDPgc= +cloud.google.com/go/firestore v1.16.0/go.mod h1:+22v/7p+WNBSQwdSwP57vz47aZiY+HrDkrOsJNhk7rg= +cloud.google.com/go/iam v1.1.13 h1:7zWBXG9ERbMLrzQBRhFliAV+kjcRToDTgQT3CTwYyv4= +cloud.google.com/go/iam v1.1.13/go.mod h1:K8mY0uSXwEXS30KrnVb+j54LB/ntfZu1dr+4zFMNbus= +cloud.google.com/go/longrunning v0.5.11 h1:Havn1kGjz3whCfoD8dxMLP73Ph5w+ODyZB9RUsDxtGk= +cloud.google.com/go/longrunning v0.5.11/go.mod h1:rDn7//lmlfWV1Dx6IB4RatCPenTwwmqXuiP0/RgoEO4= +cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= +cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= firebase.google.com/go/v4 v4.14.1 h1:4qiUETaFRWoFGE1XP5VbcEdtPX93Qs+8B/7KvP2825g= firebase.google.com/go/v4 v4.14.1/go.mod h1:fgk2XshgNDEKaioKco+AouiegSI9oTWVqRaBdTTGBoM= git.streifling.com/jason/rss v0.1.3 h1:fd3j4ZtcLehapcmmroo3AP3X34gRHC4xzpfV6bDV1ZU= @@ -22,14 +24,20 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o= github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw= +github.com/anthonynsimon/bild v0.14.0 h1:IFRkmKdNdqmexXHfEU7rPlAmdUZ8BDZEGtGHDnGWync= +github.com/anthonynsimon/bild v0.14.0/go.mod h1:hcvEAyBjTW69qkKJTfpcDQ83sSZHxwOunsseDfeQhUs= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chai2010/webp v1.1.1 h1:jTRmEccAJ4MGrhFOrPMpNGIJ/eybIgwKpcACsrTEapk= +github.com/chai2010/webp v1.1.1/go.mod h1:0XVwvZWdjjdxpUEIf7b9g9VkHFnInUSYujwqTLEuldU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -37,8 +45,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= @@ -61,8 +69,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -71,22 +77,21 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= -github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= @@ -98,119 +103,106 @@ github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02C 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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= +github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= -github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= +github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= +golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 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-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/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-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -google.golang.org/api v0.170.0 h1:zMaruDePM88zxZBG+NG8+reALO2rfLhe/JShitLyT48= -google.golang.org/api v0.170.0/go.mod h1:/xql9M2btF85xac/VAm4PsLMTLVGUOpq4BE9R8jyNy8= +google.golang.org/api v0.191.0 h1:cJcF09Z+4HAB2t5qTQM1ZtfL/PemsLFkcFG67qq2afk= +google.golang.org/api v0.191.0/go.mod h1:tD5dsFGxFza0hnQveGfVk9QQYKcfp+VzgRqyXFxE0+E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/appengine/v2 v2.0.2 h1:MSqyWy2shDLwG7chbwBJ5uMyw6SNqJzhJHNDwYB0Akk= google.golang.org/appengine/v2 v2.0.2/go.mod h1:PkgRUWz4o1XOvbqtWTkBtCitEJ5Tp4HoVEdMMYQR/8E= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c h1:kaI7oewGK5YnVwj+Y+EJBO/YN1ht8iTL9XkFHtVZLsc= -google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2 h1:9IZDv+/GcI6u+a4jRFRLxQs0RUCfavGfoOgEW6jpkI0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= +google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988 h1:CT2Thj5AuPV9phrYMtzX11k+XkzMGfRAet42PmoTATM= +google.golang.org/genproto v0.0.0-20240812133136-8ffd90a71988/go.mod h1:7uvplUBj4RjHAxIZ//98LzOvrQ04JBkaixRmCMI29hc= +google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988 h1:+/tmTy5zAieooKIXfzDm9KiA3Bv6JBwriRN9LY+yayk= +google.golang.org/genproto/googleapis/api v0.0.0-20240812133136-8ffd90a71988/go.mod h1:4+X6GvPs+25wZKbQq9qyAXrwIRExv7w0Ea6MgZLZiDM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988 h1:V71AcdLZr2p8dC9dbOIMCpqi4EmRl8wUwnJzXXLmbmc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240812133136-8ffd90a71988/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -220,10 +212,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 202d04f323c234baf2b03c0f0f5eefa4ea84a930 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 4 Oct 2024 10:11:43 +0200 Subject: [PATCH 02/10] Directly create the files []string in the correct size for HomePage --- cmd/frontend/sessions.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index b2f94de..e546a8c 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -54,19 +54,20 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { log.Fatalln(err) } - files := []string{c.WebDir + "/templates/index.html"} + files := make([]string, 2) + files[0] = c.WebDir + "/templates/index.html" if numRows == 0 { - files = append(files, c.WebDir+"/templates/first-user.html") + files[1] = c.WebDir + "/templates/first-user.html" tmpl, err := template.ParseFiles(files...) template.Must(tmpl, err).Execute(w, nil) } else { session, _ := s.Get(r, "cookie") if auth, ok := session.Values["authenticated"].(bool); auth && ok { - files = append(files, c.WebDir+"/templates/hub.html") + files[1] = c.WebDir + "/templates/hub.html" tmpl, err := template.ParseFiles(files...) template.Must(tmpl, err).Execute(w, session.Values["role"]) } else { - files = append(files, c.WebDir+"/templates/login.html") + files[1] = c.WebDir + "/templates/login.html" tmpl, err := template.ParseFiles(files...) template.Must(tmpl, err).Execute(w, nil) } From cf4d4f151a6c262768ad73ff247303dc023ce4f9 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 4 Oct 2024 10:12:35 +0200 Subject: [PATCH 03/10] No session existing is not an error; fixed --- cmd/frontend/sessions.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index e546a8c..6cdad3f 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -1,7 +1,6 @@ package frontend import ( - "errors" "fmt" "html/template" "log" @@ -41,7 +40,6 @@ func getSession(w http.ResponseWriter, r *http.Request, c *b.Config, s *b.Cookie session := &b.Session{Session: *tmpSession} if session.IsNew { template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", msg) - return session, errors.New("error: no existing session") } return session, nil From b3f31f398d078edc9248bbea47be1f61a4abb505 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 4 Oct 2024 10:21:56 +0200 Subject: [PATCH 04/10] Check for errors when executing templates --- cmd/frontend/articles.go | 84 +++++++++++++--- cmd/frontend/issues.go | 6 +- cmd/frontend/sessions.go | 46 +++++++-- cmd/frontend/{editor.go => tags.go} | 13 ++- cmd/frontend/users.go | 150 +++++++++++++++++++++++----- 5 files changed, 248 insertions(+), 51 deletions(-) rename cmd/frontend/{editor.go => tags.go} (65%) diff --git a/cmd/frontend/articles.go b/cmd/frontend/articles.go index 65a2993..5653ef2 100644 --- a/cmd/frontend/articles.go +++ b/cmd/frontend/articles.go @@ -52,7 +52,11 @@ func WriteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { } tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -120,7 +124,11 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -179,7 +187,11 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -217,7 +229,11 @@ func ShowUnpublishedUnrejectedAndPublishedRejectedArticles(c *b.Config, db *b.DB } tmpl, err := template.ParseFiles(c.WebDir + "/templates/unpublished-articles.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", articles) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", articles); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -249,7 +265,11 @@ func ShowRejectedArticles(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerF tmpl, err := template.ParseFiles(c.WebDir + "/templates/rejected-articles.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", data) + if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -305,7 +325,11 @@ func ReviewRejectedArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.Handler tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", data) + if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -390,7 +414,11 @@ func PublishArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -416,7 +444,11 @@ func RejectArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -434,7 +466,11 @@ func ShowCurrentArticles(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFu } tmpl, err := template.ParseFiles(c.WebDir + "/templates/current-articles.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", articles) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", articles); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -492,7 +528,11 @@ func ShowPublishedArticles(c *b.Config, db *b.DB, s *b.CookieStore, action strin tmpl, err := template.ParseFiles(c.WebDir + "/templates/published-articles.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", data) + if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -563,7 +603,11 @@ func ReviewArticle(c *b.Config, db *b.DB, s *b.CookieStore, action, title, butto } tmpl, err := template.ParseFiles(c.WebDir + "/templates/review-article.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -607,7 +651,11 @@ func DeleteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -659,7 +707,11 @@ func AllowEditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -714,6 +766,10 @@ func EditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { data.Action = fmt.Sprint("save/", data.Article.ID) tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } diff --git a/cmd/frontend/issues.go b/cmd/frontend/issues.go index 58aaf5b..2ae6cbd 100644 --- a/cmd/frontend/issues.go +++ b/cmd/frontend/issues.go @@ -132,7 +132,11 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index 6cdad3f..e204a76 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -33,13 +33,17 @@ func getSession(w http.ResponseWriter, r *http.Request, c *b.Config, s *b.Cookie tmpSession, err := s.Get(r, "cookie") if err != nil { - template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", msg) - return nil, err + if err = template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", msg); err != nil { + return nil, fmt.Errorf("error executing template: %v", err) + } + return nil, fmt.Errorf("error getting session: %v", err) } session := &b.Session{Session: *tmpSession} if session.IsNew { - template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", msg) + if err = template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", msg); err != nil { + return nil, fmt.Errorf("error executing template: %v", err) + } } return session, nil @@ -57,17 +61,29 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { if numRows == 0 { files[1] = c.WebDir + "/templates/first-user.html" tmpl, err := template.ParseFiles(files...) - template.Must(tmpl, err).Execute(w, nil) + if err = template.Must(tmpl, err).Execute(w, nil); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } else { session, _ := s.Get(r, "cookie") if auth, ok := session.Values["authenticated"].(bool); auth && ok { files[1] = c.WebDir + "/templates/hub.html" tmpl, err := template.ParseFiles(files...) - template.Must(tmpl, err).Execute(w, session.Values["role"]) + if err = template.Must(tmpl, err).Execute(w, session.Values["role"]); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } else { files[1] = c.WebDir + "/templates/login.html" tmpl, err := template.ParseFiles(files...) - template.Must(tmpl, err).Execute(w, nil) + if err = template.Must(tmpl, err).Execute(w, nil); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } } @@ -104,7 +120,11 @@ func Login(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { } tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user.Role) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user.Role); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -123,7 +143,11 @@ func Logout(c *b.Config, s *b.CookieStore) http.HandlerFunc { } tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -142,6 +166,10 @@ func ShowHub(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { } tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", session.Values["role"].(int)) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } diff --git a/cmd/frontend/editor.go b/cmd/frontend/tags.go similarity index 65% rename from cmd/frontend/editor.go rename to cmd/frontend/tags.go index f133e62..d3ad6a6 100644 --- a/cmd/frontend/editor.go +++ b/cmd/frontend/tags.go @@ -2,6 +2,7 @@ package frontend import ( "html/template" + "log" "net/http" b "streifling.com/jason/cpolis/cmd/backend" @@ -14,7 +15,11 @@ func CreateTag(c *b.Config, s *b.CookieStore) http.HandlerFunc { } tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-tag.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -29,6 +34,10 @@ func AddTag(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } diff --git a/cmd/frontend/users.go b/cmd/frontend/users.go index fc38db4..fba214f 100644 --- a/cmd/frontend/users.go +++ b/cmd/frontend/users.go @@ -37,7 +37,11 @@ func CreateUser(c *b.Config, s *b.CookieStore) http.HandlerFunc { } tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -70,7 +74,11 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { len(htmlData.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 { htmlData.Msg = "Alle Felder müssen ausgefüllt werden." tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } userString, stringLen, ok := checkUserStrings(htmlData.User) @@ -78,7 +86,11 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { htmlData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt.") tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } id, _ := db.GetID(htmlData.UserName) @@ -86,13 +98,21 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { htmlData.Msg = fmt.Sprint(htmlData.UserName, " ist bereits vergeben. Bitte anderen Benutzernamen wählen.") tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } if pass != pass2 { htmlData.Msg = "Die Passwörter stimmen nicht überein." tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } @@ -105,7 +125,11 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -124,7 +148,11 @@ func EditSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { } tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-self.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -152,7 +180,11 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { userData.Msg = "Alle Felder mit * müssen ausgefüllt sein." tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", userData.Msg) + if err = tmpl.ExecuteTemplate(w, "page-content", userData.Msg); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } @@ -162,7 +194,11 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { stringLen, " Zeichen erlaubt.") tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", userData) + if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } @@ -172,7 +208,11 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { userData.UserName = "" tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", userData) + if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } } @@ -187,12 +227,20 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { newPass2); err != nil { userData.Msg = "Aktualisierung der Benutzerdaten fehlgeschlagen." tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", userData) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", userData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -214,7 +262,11 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { len(htmlData.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 { htmlData.Msg = "Alle Felder müssen ausgefüllt werden." tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } userString, stringLen, ok := checkUserStrings(htmlData.User) @@ -222,7 +274,11 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { htmlData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt.") tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } id, _ := db.GetID(htmlData.UserName) @@ -230,13 +286,21 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { htmlData.Msg = fmt.Sprint(htmlData.UserName, " ist bereits vergeben. Bitte anderen Benutzernamen wählen.") tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } if pass != pass2 { htmlData.Msg = "Die Passwörter stimmen nicht überein." tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } @@ -266,7 +330,11 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { } tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", 0) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", 0); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -292,7 +360,11 @@ func ShowAllUsers(c *b.Config, db *b.DB, s *b.CookieStore, action string) http.H delete(data.Users, session.Values["id"].(int64)) tmpl, err := template.ParseFiles(c.WebDir + "/templates/show-all-users.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -317,7 +389,11 @@ func EditUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { } tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -359,7 +435,11 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { userData.Msg = "Alle Felder mit * müssen ausgefüllt sein." tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", userData.Msg) + if err = tmpl.ExecuteTemplate(w, "page-content", userData.Msg); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } @@ -369,7 +449,11 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { stringLen, " Zeichen erlaubt.") tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", userData) + if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } @@ -379,7 +463,11 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { userData.UserName = "" tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", userData) + if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } return } } @@ -394,12 +482,20 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { userData.Role); err != nil { userData.Msg = "Aktualisierung der Benutzerdaten fehlgeschlagen." tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - template.Must(tmpl, err).ExecuteTemplate(w, "page-content", userData) + if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", userData); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } @@ -425,6 +521,10 @@ func DeleteUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) - tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)) + if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } } } From 91d53a0f2a1ac706ba754b54997d32a28148ab21 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 4 Oct 2024 10:22:57 +0200 Subject: [PATCH 05/10] Get rid of unnecessary dependencies --- go.mod | 2 -- go.sum | 4 ---- 2 files changed, 6 deletions(-) diff --git a/go.mod b/go.mod index 4339332..d278c66 100644 --- a/go.mod +++ b/go.mod @@ -8,14 +8,12 @@ require ( firebase.google.com/go/v4 v4.14.1 git.streifling.com/jason/rss v0.1.3 github.com/BurntSushi/toml v1.3.2 - github.com/anthonynsimon/bild v0.14.0 github.com/chai2010/webp v1.1.1 github.com/disintegration/imaging v1.6.2 github.com/go-sql-driver/mysql v1.7.1 github.com/google/uuid v1.6.0 github.com/gorilla/sessions v1.2.2 github.com/microcosm-cc/bluemonday v1.0.26 - github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd github.com/yuin/goldmark v1.7.4 golang.org/x/crypto v0.27.0 golang.org/x/term v0.24.0 diff --git a/go.sum b/go.sum index f8445ec..d10461c 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,6 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o= github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw= -github.com/anthonynsimon/bild v0.14.0 h1:IFRkmKdNdqmexXHfEU7rPlAmdUZ8BDZEGtGHDnGWync= -github.com/anthonynsimon/bild v0.14.0/go.mod h1:hcvEAyBjTW69qkKJTfpcDQ83sSZHxwOunsseDfeQhUs= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -103,8 +101,6 @@ github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02C 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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= -github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= From c00645432b7cf86713e28730648af94a1e1b47f7 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 4 Oct 2024 10:35:32 +0200 Subject: [PATCH 06/10] Correctly handle errors from getSession --- cmd/frontend/articles.go | 30 ++++++++++++++++++++++++++++++ cmd/frontend/issues.go | 4 ++++ cmd/frontend/pdf.go | 2 ++ cmd/frontend/sessions.go | 11 ++++++++++- cmd/frontend/tags.go | 4 ++++ cmd/frontend/users.go | 16 ++++++++++++++++ 6 files changed, 66 insertions(+), 1 deletion(-) diff --git a/cmd/frontend/articles.go b/cmd/frontend/articles.go index 5653ef2..f376399 100644 --- a/cmd/frontend/articles.go +++ b/cmd/frontend/articles.go @@ -33,6 +33,8 @@ func WriteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -64,6 +66,8 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -136,6 +140,8 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -198,6 +204,8 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { func ShowUnpublishedUnrejectedAndPublishedRejectedArticles(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -241,6 +249,8 @@ func ShowRejectedArticles(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerF return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -276,6 +286,8 @@ func ShowRejectedArticles(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerF func ReviewRejectedArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -337,6 +349,8 @@ func PublishArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -426,6 +440,8 @@ func RejectArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -455,6 +471,8 @@ func RejectArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { func ShowCurrentArticles(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -477,6 +495,8 @@ func ShowCurrentArticles(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFu func UploadArticleImage(c *b.Config, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -504,6 +524,8 @@ func UploadArticleImage(c *b.Config, s *b.CookieStore) http.HandlerFunc { func ShowPublishedArticles(c *b.Config, db *b.DB, s *b.CookieStore, action string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -539,6 +561,8 @@ func ShowPublishedArticles(c *b.Config, db *b.DB, s *b.CookieStore, action strin func ReviewArticle(c *b.Config, db *b.DB, s *b.CookieStore, action, title, button string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -615,6 +639,8 @@ func DeleteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -663,6 +689,8 @@ func AllowEditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -718,6 +746,8 @@ func AllowEditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc func EditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } diff --git a/cmd/frontend/issues.go b/cmd/frontend/issues.go index 2ae6cbd..bc37616 100644 --- a/cmd/frontend/issues.go +++ b/cmd/frontend/issues.go @@ -17,6 +17,8 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -144,6 +146,8 @@ func UploadIssueImage(c *b.Config, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } diff --git a/cmd/frontend/pdf.go b/cmd/frontend/pdf.go index ac9176a..5c22204 100644 --- a/cmd/frontend/pdf.go +++ b/cmd/frontend/pdf.go @@ -15,6 +15,8 @@ import ( func UploadPDF(c *b.Config, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index e204a76..f698564 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -67,7 +67,12 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } } else { - session, _ := s.Get(r, "cookie") + session, err := getSession(w, r, c, s) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } if auth, ok := session.Values["authenticated"].(bool); auth && ok { files[1] = c.WebDir + "/templates/hub.html" tmpl, err := template.ParseFiles(files...) @@ -132,6 +137,8 @@ func Logout(c *b.Config, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -155,6 +162,8 @@ func ShowHub(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } diff --git a/cmd/frontend/tags.go b/cmd/frontend/tags.go index d3ad6a6..d7235e5 100644 --- a/cmd/frontend/tags.go +++ b/cmd/frontend/tags.go @@ -11,6 +11,8 @@ import ( func CreateTag(c *b.Config, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -27,6 +29,8 @@ func AddTag(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } diff --git a/cmd/frontend/users.go b/cmd/frontend/users.go index fba214f..36a2780 100644 --- a/cmd/frontend/users.go +++ b/cmd/frontend/users.go @@ -33,6 +33,8 @@ func checkUserStrings(user *b.User) (string, int, bool) { func CreateUser(c *b.Config, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -49,6 +51,8 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -137,6 +141,8 @@ func EditSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -160,6 +166,8 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -342,6 +350,8 @@ func ShowAllUsers(c *b.Config, db *b.DB, s *b.CookieStore, action string) http.H return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -371,6 +381,8 @@ func ShowAllUsers(c *b.Config, db *b.DB, s *b.CookieStore, action string) http.H func EditUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -401,6 +413,8 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -503,6 +517,8 @@ func DeleteUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := getSession(w, r, c, s) if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } From 533053aef0394ca93ed8b42577523bd932c9cf73 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 4 Oct 2024 11:50:51 +0200 Subject: [PATCH 07/10] Fixed a bug that prevented {{.Action}} from being acessible in editor.html --- cmd/frontend/articles.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/frontend/articles.go b/cmd/frontend/articles.go index f376399..dd1335b 100644 --- a/cmd/frontend/articles.go +++ b/cmd/frontend/articles.go @@ -38,10 +38,9 @@ func WriteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } - data := &EditorHTMLData{Action: "submit"} - + var data *EditorHTMLData if session.Values["article"] == nil { - data = &EditorHTMLData{Article: new(b.Article)} + data = &EditorHTMLData{Action: "submit", Article: new(b.Article)} } else { data = session.Values["article"].(*EditorHTMLData) } From 298ea458cad20087484a2ac3e9f03f2327187ebf Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 4 Oct 2024 11:51:24 +0200 Subject: [PATCH 08/10] Fixed login bug --- cmd/frontend/sessions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index f698564..c5bdd07 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -67,7 +67,7 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } } else { - session, err := getSession(w, r, c, s) + session, err := s.Get(r, "cookie") if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) From aec829ad85ab589ceee6c25870109c06ac8d132a Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 4 Oct 2024 12:10:12 +0200 Subject: [PATCH 09/10] Fixed a bug that returned the wrong filename for an uploaded image --- cmd/backend/images.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/backend/images.go b/cmd/backend/images.go index 367ed3a..f66c74a 100644 --- a/cmd/backend/images.go +++ b/cmd/backend/images.go @@ -23,8 +23,8 @@ func SaveImage(c *Config, src io.Reader) (string, error) { img = imaging.Resize(img, c.MaxImgWidth, 0, imaging.Lanczos) } - filename := fmt.Sprint(c.PicsDir, "/", uuid.New(), ".webp") - file, err := os.Create(filename) + filename := fmt.Sprint(uuid.New(), ".webp") + file, err := os.Create(c.PicsDir + "/" + filename) if err != nil { return "", fmt.Errorf("error creating new image file: %v", err) } From 863581f5909f35d6016c0e1145d623597dbb3d7d Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 4 Oct 2024 16:06:33 +0200 Subject: [PATCH 10/10] Show error messages in UI if something goes wrong --- cmd/backend/images.go | 6 + cmd/backend/users.go | 12 +- cmd/frontend/articles.go | 35 +++- cmd/frontend/issues.go | 23 ++- cmd/frontend/pdf.go | 18 ++ cmd/frontend/sessions.go | 4 +- cmd/frontend/tags.go | 7 +- cmd/frontend/users.go | 346 +++++++++++----------------------- web/templates/add-user.html | 7 - web/templates/editor.html | 1 + web/templates/first-user.html | 7 - web/templates/index.html | 16 +- 12 files changed, 211 insertions(+), 271 deletions(-) diff --git a/cmd/backend/images.go b/cmd/backend/images.go index f66c74a..a809b0f 100644 --- a/cmd/backend/images.go +++ b/cmd/backend/images.go @@ -2,6 +2,7 @@ package backend import ( "fmt" + "image" "io" "os" @@ -10,9 +11,14 @@ import ( "github.com/google/uuid" ) +var ErrUnsupportedFormat error = image.ErrFormat // used internally by imaging + func SaveImage(c *Config, src io.Reader) (string, error) { img, err := imaging.Decode(src, imaging.AutoOrientation(true)) if err != nil { + if err == ErrUnsupportedFormat { + return "", ErrUnsupportedFormat + } return "", fmt.Errorf("error decoding image: %v", err) } diff --git a/cmd/backend/users.go b/cmd/backend/users.go index 36dcef1..fc7bba2 100644 --- a/cmd/backend/users.go +++ b/cmd/backend/users.go @@ -47,7 +47,7 @@ func (db *DB) AddUser(u *User, pass string) (int64, error) { return id, nil } -func (db *DB) GetID(userName string) (int64, bool) { +func (db *DB) GetID(userName string) int64 { var id int64 query := ` @@ -56,11 +56,11 @@ func (db *DB) GetID(userName string) (int64, bool) { WHERE username = ? ` row := db.QueryRow(query, userName) - if err := row.Scan(&id); err != nil { - return 0, false + if err := row.Scan(&id); err != nil { // seems like the only possible error is ErrNoRows + return 0 } - return id, true + return id } func (db *DB) CheckPassword(id int64, pass string) error { @@ -146,7 +146,7 @@ func (db *DB) GetUser(id int64) (*User, error) { return user, nil } -func (db *DB) UpdateOwnAttributes(id int64, user, first, last, oldPass, newPass, newPass2 string) error { +func (db *DB) UpdateOwnUserAttributes(id int64, user, first, last, oldPass, newPass, newPass2 string) error { passwordEmpty := true if len(newPass) > 0 || len(newPass2) > 0 { if newPass != newPass2 { @@ -228,7 +228,7 @@ func (db *DB) AddFirstUser(u *User, pass string) (int64, error) { if err = tx.Commit(); err != nil { return 0, fmt.Errorf("error committing transaction: %v", err) } - return 2, nil + return -1, nil } hashedPass, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost) diff --git a/cmd/frontend/articles.go b/cmd/frontend/articles.go index dd1335b..e7dcf5c 100644 --- a/cmd/frontend/articles.go +++ b/cmd/frontend/articles.go @@ -87,6 +87,15 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { AutoGenerated: false, } + if len(article.Title) == 0 { + http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest) + return + } + if len(article.Description) == 0 { + http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest) + return + } + article.ID, err = db.AddArticle(article) if err != nil { log.Println(err) @@ -94,8 +103,14 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } + content := []byte(r.PostFormValue("article-content")) + if len(content) == 0 { + http.Error(w, "Bitte den Artikel eingeben.", http.StatusBadRequest) + return + } + articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.ID, ".md") - if err = os.WriteFile(articleAbsName, []byte(r.PostFormValue("article-content")), 0644); err != nil { + if err = os.WriteFile(articleAbsName, content, 0644); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -152,8 +167,22 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { } title := r.PostFormValue("article-title") + if len(title) == 0 { + http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest) + return + } + description := r.PostFormValue("article-description") + if len(description) == 0 { + http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest) + return + } + content := r.PostFormValue("article-content") + if len(content) == 0 { + http.Error(w, "Bitte den Artikel eingeben.", http.StatusBadRequest) + return + } link := fmt.Sprint(c.ArticleDir, "/", id, ".md") if err = os.WriteFile(link, []byte(content), 0644); err != nil { @@ -509,6 +538,10 @@ func UploadArticleImage(c *b.Config, s *b.CookieStore) http.HandlerFunc { filename, err := b.SaveImage(c, file) if err != nil { + if err == b.ErrUnsupportedFormat { + http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest) + return + } log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/cmd/frontend/issues.go b/cmd/frontend/issues.go index bc37616..f7ad2df 100644 --- a/cmd/frontend/issues.go +++ b/cmd/frontend/issues.go @@ -31,21 +31,18 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun title := r.PostFormValue("issue-title") if len(title) == 0 { - err = fmt.Errorf("error: no title for issue specified") - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest) return } if session.Values["issue-image"] == nil { - err := "error: Image required" - log.Println(err) - http.Error(w, err, http.StatusBadRequest) + http.Error(w, "Bitte ein Bild einfügen.", http.StatusBadRequest) return } imgFileName := session.Values["issue-image"].(string) - imgAbsName := fmt.Sprint(c.PicsDir, "/", imgFileName) + fmt.Println(imgFileName) + imgAbsName := c.PicsDir + "/" + imgFileName imgFile, err := os.Open(imgAbsName) if err != nil { @@ -81,8 +78,14 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun return } + content := []byte(r.PostFormValue("issue-content")) + if len(content) == 0 { + http.Error(w, "Bitte eine Beschreibung eingeben.", http.StatusBadRequest) + return + } + articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.ID, ".md") - if err = os.WriteFile(articleAbsName, []byte(r.PostFormValue("article-content")), 0644); err != nil { + if err = os.WriteFile(articleAbsName, content, 0644); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -167,6 +170,10 @@ func UploadIssueImage(c *b.Config, s *b.CookieStore) http.HandlerFunc { filename, err := b.SaveImage(c, file) if err != nil { + if err == b.ErrUnsupportedFormat { + http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest) + return + } log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/cmd/frontend/pdf.go b/cmd/frontend/pdf.go index 5c22204..0f58bb8 100644 --- a/cmd/frontend/pdf.go +++ b/cmd/frontend/pdf.go @@ -34,6 +34,24 @@ func UploadPDF(c *b.Config, s *b.CookieStore) http.HandlerFunc { } defer file.Close() + buffer := make([]byte, 512) // Should be enough for mime type + if _, err := file.Read(buffer); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if _, err := file.Seek(0, 0); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if http.DetectContentType(buffer) != "application/pdf" { + http.Error(w, "Die Datei ist kein PDF.", http.StatusInternalServerError) + return + } + filename := fmt.Sprint(uuid.New(), ".pdf") absFilepath, err := filepath.Abs(fmt.Sprint(c.PDFDir, "/", filename)) if err != nil { diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index c5bdd07..14169ce 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -99,8 +99,8 @@ func Login(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { userName := r.PostFormValue("username") password := r.PostFormValue("password") - id, ok := db.GetID(userName) - if !ok { + id := db.GetID(userName) + if id == 0 { http.Error(w, fmt.Sprintf("no such user: %v", userName), http.StatusBadRequest) return } diff --git a/cmd/frontend/tags.go b/cmd/frontend/tags.go index d7235e5..164228e 100644 --- a/cmd/frontend/tags.go +++ b/cmd/frontend/tags.go @@ -34,7 +34,12 @@ func AddTag(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } - db.AddTag(r.PostFormValue("tag")) + tag := r.PostFormValue("tag") + if len(tag) == 0 { + http.Error(w, "Bitte einen Tag eingeben.", http.StatusBadRequest) + return + } + db.AddTag(tag) tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl = template.Must(tmpl, err) diff --git a/cmd/frontend/users.go b/cmd/frontend/users.go index 36a2780..06cf1cc 100644 --- a/cmd/frontend/users.go +++ b/cmd/frontend/users.go @@ -10,11 +10,6 @@ import ( b "streifling.com/jason/cpolis/cmd/backend" ) -type UserData struct { - *b.User - Msg string -} - func checkUserStrings(user *b.User) (string, int, bool) { userLen := 15 nameLen := 50 @@ -56,71 +51,50 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } - role, err := strconv.Atoi(r.PostFormValue("role")) + user := &b.User{ + UserName: r.PostFormValue("username"), + FirstName: r.PostFormValue("first-name"), + LastName: r.PostFormValue("last-name"), + } + pass := r.PostFormValue("password") + pass2 := r.PostFormValue("password2") + + if len(user.UserName) == 0 || len(user.FirstName) == 0 || + len(user.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 { + http.Error(w, "Bitte alle Felder ausfüllen.", http.StatusBadRequest) + return + } + + userString, stringLen, ok := checkUserStrings(user) + if !ok { + http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest) + return + } + + if id := db.GetID(user.UserName); id != 0 { + http.Error(w, user.UserName+" ist bereits vergeben. Bitte anderen Benutzernamen wählen.", http.StatusBadRequest) + return + } + + if pass != pass2 { + http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest) + return + } + + roleString := r.PostFormValue("role") + if len(roleString) == 0 { + http.Error(w, "Bitte eine Aufgabe vergeben.", http.StatusBadRequest) + return + } + + user.Role, err = strconv.Atoi(roleString) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } - htmlData := UserData{ - User: &b.User{ - UserName: r.PostFormValue("username"), - FirstName: r.PostFormValue("first-name"), - LastName: r.PostFormValue("last-name"), - Role: role, - }, - } - pass := r.PostFormValue("password") - pass2 := r.PostFormValue("password2") - - if len(htmlData.UserName) == 0 || len(htmlData.FirstName) == 0 || - len(htmlData.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 { - htmlData.Msg = "Alle Felder müssen ausgefüllt werden." - tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } - userString, stringLen, ok := checkUserStrings(htmlData.User) - if !ok { - htmlData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", - stringLen, " Zeichen erlaubt.") - tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } - id, _ := db.GetID(htmlData.UserName) - if id != 0 { - htmlData.Msg = fmt.Sprint(htmlData.UserName, - " ist bereits vergeben. Bitte anderen Benutzernamen wählen.") - tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } - if pass != pass2 { - htmlData.Msg = "Die Passwörter stimmen nicht überein." - tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } - - _, err = db.AddUser(htmlData.User, pass) + _, err = db.AddUser(user, pass) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -171,75 +145,42 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } - userData := UserData{ - User: &b.User{ - ID: session.Values["id"].(int64), - UserName: r.PostFormValue("username"), - FirstName: r.PostFormValue("first-name"), - LastName: r.PostFormValue("last-name"), - }, + user := &b.User{ + ID: session.Values["id"].(int64), + UserName: r.PostFormValue("username"), + FirstName: r.PostFormValue("first-name"), + LastName: r.PostFormValue("last-name"), } + oldPass := r.PostFormValue("old-password") newPass := r.PostFormValue("password") newPass2 := r.PostFormValue("password2") - if len(userData.UserName) == 0 || len(userData.FirstName) == 0 || - len(userData.LastName) == 0 { - userData.Msg = "Alle Felder mit * müssen ausgefüllt sein." - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - tmpl = template.Must(tmpl, err) - if err = tmpl.ExecuteTemplate(w, "page-content", userData.Msg); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + if len(user.UserName) == 0 { + http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusBadRequest) return } - userString, stringLen, ok := checkUserStrings(userData.User) + if len(user.FirstName) == 0 || len(user.LastName) == 0 { + http.Error(w, "Bitte den vollständigen Namen ausfüllen.", http.StatusBadRequest) + return + } + + userString, stringLen, ok := checkUserStrings(user) if !ok { - userData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", - stringLen, " Zeichen erlaubt.") - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - tmpl = template.Must(tmpl, err) - if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest) return } - if id, ok := db.GetID(userData.UserName); ok { - if id != userData.ID { - userData.Msg = "Benutzername bereits vergeben." - userData.UserName = "" - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - tmpl = template.Must(tmpl, err) - if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } + if id := db.GetID(user.UserName); id != 0 && id != user.ID { + http.Error(w, user.UserName+" ist bereits vergeben. Bitte anderen Benutzernamen wählen.", http.StatusBadRequest) + return } - if err = db.UpdateOwnAttributes( - userData.ID, - userData.UserName, - userData.FirstName, - userData.LastName, - oldPass, - newPass, - newPass2); err != nil { - userData.Msg = "Aktualisierung der Benutzerdaten fehlgeschlagen." - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", userData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + if err = db.UpdateOwnUserAttributes(user.ID, user.UserName, user.FirstName, user.LastName, oldPass, newPass, newPass2); err != nil { + log.Println("error: user:", user.ID, err) + http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError) + return } tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") @@ -255,77 +196,44 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var err error - htmlData := UserData{ - User: &b.User{ - UserName: r.PostFormValue("username"), - FirstName: r.PostFormValue("first-name"), - LastName: r.PostFormValue("last-name"), - Role: b.Admin, - }, + user := &b.User{ + UserName: r.PostFormValue("username"), + FirstName: r.PostFormValue("first-name"), + LastName: r.PostFormValue("last-name"), + Role: b.Admin, } pass := r.PostFormValue("password") pass2 := r.PostFormValue("password2") - if len(htmlData.UserName) == 0 || len(htmlData.FirstName) == 0 || - len(htmlData.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 { - htmlData.Msg = "Alle Felder müssen ausgefüllt werden." - tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } - userString, stringLen, ok := checkUserStrings(htmlData.User) - if !ok { - htmlData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", - stringLen, " Zeichen erlaubt.") - tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } - id, _ := db.GetID(htmlData.UserName) - if id != 0 { - htmlData.Msg = fmt.Sprint(htmlData.UserName, - " ist bereits vergeben. Bitte anderen Benutzernamen wählen.") - tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } - if pass != pass2 { - htmlData.Msg = "Die Passwörter stimmen nicht überein." - tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") - if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + if len(user.UserName) == 0 || len(user.FirstName) == 0 || + len(user.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 { + http.Error(w, "Bitte alle Felder ausfüllen.", http.StatusBadRequest) return } - htmlData.ID, err = db.AddFirstUser(htmlData.User, pass) + userString, stringLen, ok := checkUserStrings(user) + if !ok { + http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest) + return + } + + if pass != pass2 { + http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest) + return + } + + user.ID, err = db.AddFirstUser(user, pass) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } - if htmlData.ID > 1 { - errString := "error: there is already a first user" - log.Println(errString) - http.Error(w, errString, http.StatusInternalServerError) + if user.ID == -1 { + http.Error(w, "Bitte ein Benutzerkonto von einem Administrator anlegen lassen.", http.StatusInternalServerError) return } - if err := saveSession(w, r, s, htmlData.User); err != nil { + if err := saveSession(w, r, s, user); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -418,93 +326,55 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } - id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) + user := new(b.User) + user.ID, err = strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } - role, err := strconv.Atoi(r.PostFormValue("role")) + user.Role, err = strconv.Atoi(r.PostFormValue("role")) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } - userData := UserData{ - User: &b.User{ - ID: id, - UserName: r.PostFormValue("username"), - FirstName: r.PostFormValue("first-name"), - LastName: r.PostFormValue("last-name"), - Role: role, - }, + user.UserName = r.PostFormValue("username") + if len(user.UserName) == 0 { + http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusInternalServerError) + return } + + user.FirstName = r.PostFormValue("first-name") + user.LastName = r.PostFormValue("last-name") + if len(user.FirstName) == 0 || len(user.LastName) == 0 { + http.Error(w, "Bitte den vollständigen Namen ausfüllen.", http.StatusInternalServerError) + return + } + newPass := r.PostFormValue("password") newPass2 := r.PostFormValue("password2") - if len(userData.UserName) == 0 || len(userData.FirstName) == 0 || - len(userData.LastName) == 0 { - userData.Msg = "Alle Felder mit * müssen ausgefüllt sein." - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - tmpl = template.Must(tmpl, err) - if err = tmpl.ExecuteTemplate(w, "page-content", userData.Msg); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } - - userString, stringLen, ok := checkUserStrings(userData.User) + userString, stringLen, ok := checkUserStrings(user) if !ok { - userData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", - stringLen, " Zeichen erlaubt.") - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - tmpl = template.Must(tmpl, err) - if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest) return } - if id, ok := db.GetID(userData.UserName); ok { - if id != userData.ID { - userData.Msg = "Benutzername bereits vergeben." - userData.UserName = "" - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - tmpl = template.Must(tmpl, err) - if err = tmpl.ExecuteTemplate(w, "page-content", userData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - return - } + if id := db.GetID(user.UserName); id != 0 && id != user.ID { + http.Error(w, user.UserName+" ist bereits vergeben. Bitte anderen Benutzernamen wählen.", http.StatusBadRequest) + return } - if err = db.UpdateUserAttributes( - userData.ID, - userData.UserName, - userData.FirstName, - userData.LastName, - newPass, - newPass2, - userData.Role); err != nil { - userData.Msg = "Aktualisierung der Benutzerdaten fehlgeschlagen." - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") - if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", userData); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + if err = db.UpdateUserAttributes(user.ID, user.UserName, user.FirstName, user.LastName, newPass, newPass2, user.Role); err != nil { + log.Println("error: user:", user.ID, err) + http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError) + return } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") - tmpl = template.Must(tmpl, err) + tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html")) if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/web/templates/add-user.html b/web/templates/add-user.html index d6aeae9..1c5847d 100644 --- a/web/templates/add-user.html +++ b/web/templates/add-user.html @@ -49,11 +49,4 @@ - - {{end}} diff --git a/web/templates/editor.html b/web/templates/editor.html index ca433cc..e6d9bcd 100644 --- a/web/templates/editor.html +++ b/web/templates/editor.html @@ -64,6 +64,7 @@ onSuccess(data); }) .catch(error => { + htmx.trigger(htmx.find('#notification'), 'htmx:responseError', {xhr: {responseText: error.message}}); onError(error); }); }, diff --git a/web/templates/first-user.html b/web/templates/first-user.html index b22e4cb..4fb84f2 100644 --- a/web/templates/first-user.html +++ b/web/templates/first-user.html @@ -29,11 +29,4 @@ - - {{end}} diff --git a/web/templates/index.html b/web/templates/index.html index 95c394a..7d60954 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -28,6 +28,10 @@
+ +
{{template "page-content" .}}
@@ -35,7 +39,7 @@

© 2024 Jason Streifling. Alle Rechte vorbehalten.

-

v0.11.1 - Alpha: Drastische Änderungen und Fehler vorbehalten.

+

v0.12.0 - Alpha: Drastische Änderungen und Fehler vorbehalten.

@@ -66,6 +70,16 @@ }); }); +