From 2fd053a077e0502956b188dc3e3e4a3828b8b103 Mon Sep 17 00:00:00 2001 From: John Olheiser Date: Sat, 11 May 2024 14:03:25 -0500 Subject: [PATCH] feat: make edit visibility a toggle (#277) * feat: make edit visibility a toggle Signed-off-by: jolheiser * Tweak SVG dropdown icon size & color --------- Signed-off-by: jolheiser Co-authored-by: Thomas Miceli --- internal/db/gist.go | 18 ++++++---- internal/web/gist.go | 23 +++++++----- internal/web/server.go | 9 ++--- internal/web/test/gist_test.go | 65 +++++++++++++++++++++------------- internal/web/test/server.go | 23 +++++++----- templates/pages/edit.html | 30 +++++++++------- 6 files changed, 102 insertions(+), 66 deletions(-) diff --git a/internal/db/gist.go b/internal/db/gist.go index 276dcad..5b26934 100644 --- a/internal/db/gist.go +++ b/internal/db/gist.go @@ -538,13 +538,17 @@ func (gist *Gist) GetLanguagesFromFiles() ([]string, error) { // -- DTO -- // type GistDTO struct { - Title string `validate:"max=250" form:"title"` - Description string `validate:"max=1000" form:"description"` - URL string `validate:"max=32,alphanumdashorempty" form:"url"` - Private Visibility `validate:"number,min=0,max=2" form:"private"` - Files []FileDTO `validate:"min=1,dive"` - Name []string `form:"name"` - Content []string `form:"content"` + Title string `validate:"max=250" form:"title"` + Description string `validate:"max=1000" form:"description"` + URL string `validate:"max=32,alphanumdashorempty" form:"url"` + Files []FileDTO `validate:"min=1,dive"` + Name []string `form:"name"` + Content []string `form:"content"` + VisibilityDTO +} + +type VisibilityDTO struct { + Private Visibility `validate:"number,min=0,max=2" form:"private"` } type FileDTO struct { diff --git a/internal/web/gist.go b/internal/web/gist.go index 4161d59..1178437 100644 --- a/internal/web/gist.go +++ b/internal/web/gist.go @@ -6,12 +6,6 @@ import ( "bytes" "errors" "fmt" - "github.com/rs/zerolog/log" - "github.com/thomiceli/opengist/internal/git" - "github.com/thomiceli/opengist/internal/i18n" - "github.com/thomiceli/opengist/internal/index" - "github.com/thomiceli/opengist/internal/render" - "github.com/thomiceli/opengist/internal/utils" "html/template" "net/url" "path/filepath" @@ -20,6 +14,13 @@ import ( "strings" "time" + "github.com/rs/zerolog/log" + "github.com/thomiceli/opengist/internal/git" + "github.com/thomiceli/opengist/internal/i18n" + "github.com/thomiceli/opengist/internal/index" + "github.com/thomiceli/opengist/internal/render" + "github.com/thomiceli/opengist/internal/utils" + "github.com/google/uuid" "github.com/labstack/echo/v4" "github.com/thomiceli/opengist/internal/config" @@ -603,10 +604,15 @@ func processCreate(ctx echo.Context) error { return redirect(ctx, "/"+user.Username+"/"+gist.Identifier()) } -func toggleVisibility(ctx echo.Context) error { +func editVisibility(ctx echo.Context) error { gist := getData(ctx, "gist").(*db.Gist) - gist.Private = (gist.Private + 1) % 3 + dto := new(db.VisibilityDTO) + if err := ctx.Bind(dto); err != nil { + return errorRes(400, tr(ctx, "error.cannot-bind-data"), err) + } + + gist.Private = dto.Private if err := gist.UpdateNoTimestamps(); err != nil { return errorRes(500, "Error updating this gist", err) } @@ -733,7 +739,6 @@ func downloadFile(ctx echo.Context) error { ctx.Response().Header().Set("Content-Disposition", "attachment; filename="+file.Filename) ctx.Response().Header().Set("Content-Length", strconv.Itoa(len(file.Content))) _, err = ctx.Response().Write([]byte(file.Content)) - if err != nil { return errorRes(500, "Error downloading the file", err) } diff --git a/internal/web/server.go b/internal/web/server.go index 384fe81..3d3ad7d 100644 --- a/internal/web/server.go +++ b/internal/web/server.go @@ -5,9 +5,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/thomiceli/opengist/internal/index" - "github.com/thomiceli/opengist/internal/utils" - "github.com/thomiceli/opengist/templates" htmlpkg "html" "html/template" "io" @@ -21,6 +18,10 @@ import ( "strings" "time" + "github.com/thomiceli/opengist/internal/index" + "github.com/thomiceli/opengist/internal/utils" + "github.com/thomiceli/opengist/templates" + "github.com/gorilla/sessions" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" @@ -313,7 +314,7 @@ func NewServer(isDev bool) *Server { g3.GET("/rev/:revision", gistIndex) g3.GET("/revisions", revisions) g3.GET("/archive/:revision", downloadZip) - g3.POST("/visibility", toggleVisibility, logged, writePermission) + g3.POST("/visibility", editVisibility, logged, writePermission) g3.POST("/delete", deleteGist, logged, writePermission) g3.GET("/raw/:revision/:file", rawFile) g3.GET("/download/:revision/:file", downloadFile) diff --git a/internal/web/test/gist_test.go b/internal/web/test/gist_test.go index a04f906..840753b 100644 --- a/internal/web/test/gist_test.go +++ b/internal/web/test/gist_test.go @@ -1,10 +1,11 @@ package test import ( + "testing" + "github.com/stretchr/testify/require" "github.com/thomiceli/opengist/internal/db" "github.com/thomiceli/opengist/internal/git" - "testing" ) func TestGists(t *testing.T) { @@ -28,9 +29,11 @@ func TestGists(t *testing.T) { gist1 := db.GistDTO{ Title: "gist1", Description: "my first gist", - Private: 0, - Name: []string{"gist1.txt", "gist2.txt", "gist3.txt"}, - Content: []string{"yeah", "yeah\ncool", "yeah\ncool gist actually"}, + VisibilityDTO: db.VisibilityDTO{ + Private: 0, + }, + Name: []string{"gist1.txt", "gist2.txt", "gist3.txt"}, + Content: []string{"yeah", "yeah\ncool", "yeah\ncool gist actually"}, } err = s.request("POST", "/", gist1, 302) require.NoError(t, err) @@ -57,9 +60,11 @@ func TestGists(t *testing.T) { gist2 := db.GistDTO{ Title: "gist2", Description: "my second gist", - Private: 0, - Name: []string{"", "gist2.txt", "gist3.txt"}, - Content: []string{"", "yeah\ncool", "yeah\ncool gist actually"}, + VisibilityDTO: db.VisibilityDTO{ + Private: 0, + }, + Name: []string{"", "gist2.txt", "gist3.txt"}, + Content: []string{"", "yeah\ncool", "yeah\ncool gist actually"}, } err = s.request("POST", "/", gist2, 200) require.NoError(t, err) @@ -67,9 +72,11 @@ func TestGists(t *testing.T) { gist3 := db.GistDTO{ Title: "gist3", Description: "my third gist", - Private: 0, - Name: []string{""}, - Content: []string{"yeah"}, + VisibilityDTO: db.VisibilityDTO{ + Private: 0, + }, + Name: []string{""}, + Content: []string{"yeah"}, } err = s.request("POST", "/", gist3, 302) require.NoError(t, err) @@ -110,9 +117,11 @@ func TestVisibility(t *testing.T) { gist1 := db.GistDTO{ Title: "gist1", Description: "my first gist", - Private: db.UnlistedVisibility, - Name: []string{""}, - Content: []string{"yeah"}, + VisibilityDTO: db.VisibilityDTO{ + Private: db.UnlistedVisibility, + }, + Name: []string{""}, + Content: []string{"yeah"}, } err = s.request("POST", "/", gist1, 302) require.NoError(t, err) @@ -121,19 +130,19 @@ func TestVisibility(t *testing.T) { require.NoError(t, err) require.Equal(t, db.UnlistedVisibility, gist1db.Private) - err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/visibility", nil, 302) + err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/visibility", db.VisibilityDTO{Private: db.PrivateVisibility}, 302) require.NoError(t, err) gist1db, err = db.GetGistByID("1") require.NoError(t, err) require.Equal(t, db.PrivateVisibility, gist1db.Private) - err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/visibility", nil, 302) + err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/visibility", db.VisibilityDTO{Private: db.PublicVisibility}, 302) require.NoError(t, err) gist1db, err = db.GetGistByID("1") require.NoError(t, err) require.Equal(t, db.PublicVisibility, gist1db.Private) - err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/visibility", nil, 302) + err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/visibility", db.VisibilityDTO{Private: db.UnlistedVisibility}, 302) require.NoError(t, err) gist1db, err = db.GetGistByID("1") require.NoError(t, err) @@ -152,9 +161,11 @@ func TestLikeFork(t *testing.T) { gist1 := db.GistDTO{ Title: "gist1", Description: "my first gist", - Private: 1, - Name: []string{""}, - Content: []string{"yeah"}, + VisibilityDTO: db.VisibilityDTO{ + Private: 1, + }, + Name: []string{""}, + Content: []string{"yeah"}, } err = s.request("POST", "/", gist1, 302) require.NoError(t, err) @@ -212,9 +223,11 @@ func TestCustomUrl(t *testing.T) { Title: "gist1", URL: "my-gist", Description: "my first gist", - Private: 0, - Name: []string{"gist1.txt", "gist2.txt", "gist3.txt"}, - Content: []string{"yeah", "yeah\ncool", "yeah\ncool gist actually"}, + VisibilityDTO: db.VisibilityDTO{ + Private: 0, + }, + Name: []string{"gist1.txt", "gist2.txt", "gist3.txt"}, + Content: []string{"yeah", "yeah\ncool", "yeah\ncool gist actually"}, } err = s.request("POST", "/", gist1, 302) require.NoError(t, err) @@ -241,9 +254,11 @@ func TestCustomUrl(t *testing.T) { gist2 := db.GistDTO{ Title: "gist2", Description: "my second gist", - Private: 0, - Name: []string{"gist1.txt", "gist2.txt", "gist3.txt"}, - Content: []string{"yeah", "yeah\ncool", "yeah\ncool gist actually"}, + VisibilityDTO: db.VisibilityDTO{ + Private: 0, + }, + Name: []string{"gist1.txt", "gist2.txt", "gist3.txt"}, + Content: []string{"yeah", "yeah\ncool", "yeah\ncool gist actually"}, } err = s.request("POST", "/", gist2, 302) require.NoError(t, err) diff --git a/internal/web/test/server.go b/internal/web/test/server.go index 5bcf224..5ef8d25 100644 --- a/internal/web/test/server.go +++ b/internal/web/test/server.go @@ -3,13 +3,6 @@ package test import ( "errors" "fmt" - "github.com/rs/zerolog/log" - "github.com/stretchr/testify/require" - "github.com/thomiceli/opengist/internal/config" - "github.com/thomiceli/opengist/internal/db" - "github.com/thomiceli/opengist/internal/git" - "github.com/thomiceli/opengist/internal/memdb" - "github.com/thomiceli/opengist/internal/web" "io" "net/http" "net/http/httptest" @@ -21,6 +14,14 @@ import ( "strconv" "strings" "testing" + + "github.com/rs/zerolog/log" + "github.com/stretchr/testify/require" + "github.com/thomiceli/opengist/internal/config" + "github.com/thomiceli/opengist/internal/db" + "github.com/thomiceli/opengist/internal/git" + "github.com/thomiceli/opengist/internal/memdb" + "github.com/thomiceli/opengist/internal/web" ) type testServer struct { @@ -106,7 +107,7 @@ func structToURLValues(s interface{}) url.Values { for i := 0; i < rValue.NumField(); i++ { field := rValue.Type().Field(i) tag := field.Tag.Get("form") - if tag != "" { + if tag != "" || field.Anonymous { if field.Type.Kind() == reflect.Int { fieldValue := rValue.Field(i).Int() v.Add(tag, strconv.FormatInt(fieldValue, 10)) @@ -115,6 +116,12 @@ func structToURLValues(s interface{}) url.Values { for _, va := range fieldValue { v.Add(tag, va) } + } else if field.Type.Kind() == reflect.Struct { + for key, val := range structToURLValues(rValue.Field(i).Interface()) { + for _, vv := range val { + v.Add(key, vv) + } + } } else { fieldValue := rValue.Field(i).String() v.Add(tag, fieldValue) diff --git a/templates/pages/edit.html b/templates/pages/edit.html index c80f769..a8f92d6 100644 --- a/templates/pages/edit.html +++ b/templates/pages/edit.html @@ -10,19 +10,23 @@
{{ .csrfHtml }} - +
+ +
+ + +
+
{{ .csrfHtml }}