From 5ab8633cf5b5167d3c354d925169b5518a6bc7eb Mon Sep 17 00:00:00 2001 From: Kelly Wong Date: Wed, 20 Mar 2024 21:50:40 +0800 Subject: [PATCH 01/17] inital stories moderation --- .env.example | 18 ---- controller/stories/stories.go | 66 +++++++++++++++ controller/stories/update.go | 62 ++++++++++++++ go.mod | 16 +++- go.sum | 48 +++++++++++ internal/auth/middleware.go | 7 +- internal/permissiongroups/stories/stories.go | 5 ++ internal/permissions/users/permissions.go | 1 + internal/permissions/users/role.go | 2 + internal/permissions/users/users.go | 1 + internal/router/router.go | 7 +- migrations/20230807190030-add_status.sql | 9 ++ model/stories.go | 86 ++++++++++++++++---- model/usergroups.go | 15 ++++ params/stories/moderate.go | 28 +++++++ 15 files changed, 332 insertions(+), 39 deletions(-) delete mode 100644 .env.example create mode 100644 migrations/20230807190030-add_status.sql create mode 100644 params/stories/moderate.go diff --git a/.env.example b/.env.example deleted file mode 100644 index 042807b..0000000 --- a/.env.example +++ /dev/null @@ -1,18 +0,0 @@ -HOST=localhost -PORT=8080 - -DB_TIMEZONE=Asia/Singapore -DB_HOSTNAME=localhost -DB_PORT=5432 -DB_USERNAME=postgres -DB_PASSWORD= -DB_NAME= - -SENTRY_DSN= - -JWKS_ENDPOINT= - -# only for non-development mode -ALLOWED_ORIGIN_1= -ALLOWED_ORIGIN_2= -# ... and so on diff --git a/controller/stories/stories.go b/controller/stories/stories.go index aed024e..4453614 100644 --- a/controller/stories/stories.go +++ b/controller/stories/stories.go @@ -54,6 +54,72 @@ func HandleList(w http.ResponseWriter, r *http.Request) error { return nil } +func HandleListPublished(w http.ResponseWriter, r *http.Request) error { + err := auth.CheckPermissions(r, storypermissiongroups.List()) + if err != nil { + logrus.Error(err) + return apierrors.ClientForbiddenError{ + Message: fmt.Sprintf("Error listing stories: %v", err), + } + } + + // Get DB instance + db, err := database.GetDBFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + // Get group id from context + groupID, err := usergroups.GetGroupIDFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + stories, err := model.GetAllPublishedStories(db, groupID) + if err != nil { + logrus.Error(err) + return err + } + + controller.EncodeJSONResponse(w, storyviews.ListFrom(stories)) + return nil +} + +func HandleListDraft(w http.ResponseWriter, r *http.Request) error { + err := auth.CheckPermissions(r, storypermissiongroups.List()) + if err != nil { + logrus.Error(err) + return apierrors.ClientForbiddenError{ + Message: fmt.Sprintf("Error listing stories: %v", err), + } + } + + // Get DB instance + db, err := database.GetDBFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + // Get group id from context + groupID, err := usergroups.GetGroupIDFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + stories, err := model.GetAllDraftStories(db, groupID) + if err != nil { + logrus.Error(err) + return err + } + + controller.EncodeJSONResponse(w, storyviews.ListFrom(stories)) + return nil +} + func HandleRead(w http.ResponseWriter, r *http.Request) error { storyIDStr := chi.URLParam(r, "storyID") storyID, err := strconv.Atoi(storyIDStr) diff --git a/controller/stories/update.go b/controller/stories/update.go index 3079e67..61dda32 100644 --- a/controller/stories/update.go +++ b/controller/stories/update.go @@ -85,3 +85,65 @@ func HandleUpdate(w http.ResponseWriter, r *http.Request) error { controller.EncodeJSONResponse(w, storyviews.SingleFrom(storyModel)) return nil } + +func HandlePublish(w http.ResponseWriter, r *http.Request) error { + storyIDStr := chi.URLParam(r, "storyID") + storyID, err := strconv.Atoi(storyIDStr) + if err != nil { + return apierrors.ClientBadRequestError{ + Message: fmt.Sprintf("Invalid storyID: %v", err), + } + } + + err = auth.CheckPermissions(r, storypermissiongroups.Publish()) + if err != nil { + logrus.Error(err) + return apierrors.ClientForbiddenError{ + Message: fmt.Sprintf("Error moderating story: %v", err), + } + } + + // Extra params won't do anything, e.g. authorID can't be changed. + // TODO: Error on extra params? + var params storyparams.Update + if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { + e, ok := err.(*json.UnmarshalTypeError) + if !ok { + logrus.Error(err) + return apierrors.ClientBadRequestError{ + Message: fmt.Sprintf("Bad JSON parsing: %v", err), + } + } + + // TODO: Investigate if we should use errors.Wrap instead + return apierrors.ClientUnprocessableEntityError{ + Message: fmt.Sprintf("Invalid JSON format: %s should be a %s.", e.Field, e.Type), + } + } + + err = params.Validate() + if err != nil { + logrus.Error(err) + return apierrors.ClientUnprocessableEntityError{ + Message: fmt.Sprintf("JSON validation failed: %v", err), + } + } + + storyModel := *params.ToModel() + + // Get DB instance + db, err := database.GetDBFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + err = model.UpdateStory(db, storyID, &storyModel) + if err != nil { + logrus.Error(err) + return err + } + + controller.EncodeJSONResponse(w, storyviews.SingleFrom(storyModel)) + return nil +} \ No newline at end of file diff --git a/go.mod b/go.mod index 9a7d32c..d39159e 100644 --- a/go.mod +++ b/go.mod @@ -19,11 +19,13 @@ require ( ) require ( + github.com/BurntSushi/toml v1.2.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jinzhu/inflection v1.0.0 // indirect @@ -38,8 +40,20 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/segmentio/asm v1.2.0 // indirect + github.com/sergi/go-diff v1.1.0 // indirect + github.com/zmb3/gogetdoc v0.0.0-20190228002656-b37376c5da6a // indirect golang.org/x/crypto v0.17.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338 // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/telemetry v0.0.0-20231114163143-69313e640400 // indirect golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.17.0 // indirect + golang.org/x/tools/gopls v0.14.2 // indirect + golang.org/x/vuln v1.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + honnef.co/go/tools v0.4.5 // indirect + mvdan.cc/gofumpt v0.4.0 // indirect + mvdan.cc/xurls/v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 00f7ef2..3f033f1 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/TwiN/go-color v1.4.0 h1:fNbOwOrvup5oj934UragnW0B1WKaAkkB85q19Y7h4ng= github.com/TwiN/go-color v1.4.0/go.mod h1:0QTVEPlu+AoCyTrho7bXbVkrCkVpdQr7YF7PYWEtSxM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -25,6 +27,7 @@ github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XE github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= @@ -38,7 +41,10 @@ github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= @@ -61,22 +67,27 @@ github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 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/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rubenv/sql-migrate v1.5.1 h1:WsZo4jPQfjmddDTh/suANP2aKPA7/ekN0LzuuajgQEo= github.com/rubenv/sql-migrate v1.5.1/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -84,21 +95,34 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO 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/zmb3/gogetdoc v0.0.0-20190228002656-b37376c5da6a h1:00UFliGZl2UciXe8o/2iuEsRQ9u7z0rzDTVzuj6EYY0= +github.com/zmb3/gogetdoc v0.0.0-20190228002656-b37376c5da6a/go.mod h1:ofmGw6LrMypycsiWcyug6516EXpIxSbZ+uI9ppGypfY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338 h1:2O2DON6y3XMJiQRAS1UWU+54aec2uopH3x7MAiqGW6Y= +golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -110,6 +134,10 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20231114163143-69313e640400 h1:brbkEFfGwNGAEkykUOcryE/JiHUMMJouzE0fWWmz/QU= +golang.org/x/telemetry v0.0.0-20231114163143-69313e640400/go.mod h1:P6hMdmAcoG7FyATwqSr6R/U0n7yeXNP/QXeRlxb1szE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -123,12 +151,26 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181207195948-8634b1ecd393/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.14.1-0.20231114185516-c9d3e7de13fd h1:Oku7E+OCrXHyst1dG1z10etCTxewCHXNFLRlyMPbh3w= +golang.org/x/tools v0.14.1-0.20231114185516-c9d3e7de13fd/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools/gopls v0.14.2 h1:sIw6vjZiuQ9S7s0auUUkHlWgsCkKZFWDHmrge8LYsnc= +golang.org/x/tools/gopls v0.14.2/go.mod h1:o2s+suLlFye+MHxEofsxJPkBQ/kT/ucP4iJV3ohjGEQ= +golang.org/x/vuln v1.0.1 h1:KUas02EjQK5LTuIx1OylBQdKKZ9jeugs+HiqO5HormU= +golang.org/x/vuln v1.0.1/go.mod h1:bb2hMwln/tqxg32BNY4CcxHWtHXuYa3SbIBmtsyjxtM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -136,3 +178,9 @@ gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +honnef.co/go/tools v0.4.5 h1:YGD4H+SuIOOqsyoLOpZDWcieM28W47/zRO7f+9V3nvo= +honnef.co/go/tools v0.4.5/go.mod h1:GUV+uIBCLpdf0/v6UhHHG/yzI/z6qPskBeQCjcNB96k= +mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM= +mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= +mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc= +mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg= diff --git a/internal/auth/middleware.go b/internal/auth/middleware.go index 88987e3..85e01db 100644 --- a/internal/auth/middleware.go +++ b/internal/auth/middleware.go @@ -28,8 +28,11 @@ func MakeMiddlewareFrom(conf *config.Config) func(http.Handler) http.Handler { // Skip auth in development mode if conf.Environment == envutils.ENV_DEVELOPMENT { return func(next http.Handler) http.Handler { - return next - } + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r = injectUserIDToContext(r, 1) + next.ServeHTTP(w, r) + }) + } } keySet := getJWKS(conf.JWKSEndpoint) diff --git a/internal/permissiongroups/stories/stories.go b/internal/permissiongroups/stories/stories.go index 06ddcbd..5d38811 100644 --- a/internal/permissiongroups/stories/stories.go +++ b/internal/permissiongroups/stories/stories.go @@ -20,6 +20,11 @@ func Read() permissions.PermissionGroup { GetRolePermission(userpermissions.CanReadStories) } +func Publish() permissions.PermissionGroup { + return userpermissions. + GetRolePermission(userpermissions.CanPublishStories) +} + func Update(storyID uint) permissions.PermissionGroup { return permissions.AnyOf{ Groups: []permissions.PermissionGroup{ diff --git a/internal/permissions/users/permissions.go b/internal/permissions/users/permissions.go index bc0a2f7..a5673bb 100644 --- a/internal/permissions/users/permissions.go +++ b/internal/permissions/users/permissions.go @@ -17,4 +17,5 @@ const ( CanReadStories Permission = "can_read_stories" CanUpdateStories Permission = "can_update_stories" CanDeleteStories Permission = "can_delete_stories" + CanPublishStories Permission = "can_publish_stories" ) diff --git a/internal/permissions/users/role.go b/internal/permissions/users/role.go index c0dccc7..0e0c7c4 100644 --- a/internal/permissions/users/role.go +++ b/internal/permissions/users/role.go @@ -19,3 +19,5 @@ func (p RolePermission) IsAuthorized(r *http.Request) bool { } return groupenums.IsRoleGreaterThan(*role, p.Role) } + + diff --git a/internal/permissions/users/users.go b/internal/permissions/users/users.go index a6e8b8b..d4c4992 100644 --- a/internal/permissions/users/users.go +++ b/internal/permissions/users/users.go @@ -23,6 +23,7 @@ func GetRolePermission(p Permission) *RolePermission { case // Additional permissions for moderators and administrators CanUpdateStories, + CanPublishStories, CanDeleteStories: return &RolePermission{ Permission: p, diff --git a/internal/router/router.go b/internal/router/router.go index 891e9e8..78f4ff8 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -55,18 +55,21 @@ func Setup(config *config.Config, injectMiddleWares []func(http.Handler) http.Ha r.Use(usergroups.InjectUserGroupIntoContext) r.Route("/stories", func(r chi.Router) { r.Get("/", handleAPIError(stories.HandleList)) + r.Get("/draft", handleAPIError(stories.HandleListDraft)) + r.Get("/published", handleAPIError(stories.HandleListPublished)) r.Get("/{storyID}", handleAPIError(stories.HandleRead)) r.Put("/{storyID}", handleAPIError(stories.HandleUpdate)) + r.Put("/{storyID}/publish", handleAPIError(stories.HandlePublish)) r.Delete("/{storyID}", handleAPIError(stories.HandleDelete)) r.Post("/", handleAPIError(stories.HandleCreate)) - }) + }) r.Route("/users", func(r chi.Router) { r.Get("/", handleAPIError(users.HandleList)) r.Get("/{userID}", handleAPIError(users.HandleRead)) r.Delete("/{userID}", handleAPIError(users.HandleDelete)) r.Post("/", handleAPIError(users.HandleCreate)) - r.Post("/batch", handleAPIError(usergroupscontroller.HandleBatchCreate)) + r.Put("/batch", handleAPIError(usergroupscontroller.HandleBatchCreate)) }) }) diff --git a/migrations/20230807190030-add_status.sql b/migrations/20230807190030-add_status.sql new file mode 100644 index 0000000..8cf8060 --- /dev/null +++ b/migrations/20230807190030-add_status.sql @@ -0,0 +1,9 @@ +-- +migrate Up + +ALTER TABLE stories + ADD COLUMN status INT; + +-- +migrate Down + +ALTER TABLE stories + DROP COLUMN status; \ No newline at end of file diff --git a/model/stories.go b/model/stories.go index a3ccc07..bcade9e 100644 --- a/model/stories.go +++ b/model/stories.go @@ -1,20 +1,31 @@ package model import ( + "fmt" + "github.com/source-academy/stories-backend/internal/database" + groupenums "github.com/source-academy/stories-backend/internal/enums/groups" "gorm.io/gorm" "gorm.io/gorm/clause" ) +type StoryStatus int + +const ( + Draft StoryStatus = iota + Published +) + type Story struct { - gorm.Model - AuthorID uint - Author User - GroupID *uint // null means this is a public story - Group Group - Title string - Content string - PinOrder *int // nil if not pinned + gorm.Model + AuthorID uint + Author User + GroupID *uint + Group Group + Title string + Content string + PinOrder *int + Status StoryStatus } // Passing nil to omit the filtering and get all stories @@ -35,6 +46,38 @@ func GetAllStoriesInGroup(db *gorm.DB, groupID *uint) ([]Story, error) { return stories, nil } +func GetAllPublishedStories(db *gorm.DB, groupID *uint) ([]Story, error) { + var stories []Story + err := db. + // FIXME: Handle nil case properly + Where(Story{GroupID: groupID, Status: Published}). + Preload(clause.Associations). + // TODO: Abstract out the sorting logic + Order("pin_order ASC NULLS LAST, title ASC, content ASC"). + Find(&stories). + Error + if err != nil { + return stories, database.HandleDBError(err, "story") + } + return stories, nil +} + +func GetAllDraftStories(db *gorm.DB, groupID *uint) ([]Story, error) { + var stories []Story + err := db. + // FIXME: Handle nil case properly + Where(Story{GroupID: groupID, Status: Draft}). + Preload(clause.Associations). + // TODO: Abstract out the sorting logic + Order("pin_order ASC NULLS LAST, title ASC, content ASC"). + Find(&stories). + Error + if err != nil { + return stories, database.HandleDBError(err, "story") + } + return stories, nil +} + func GetStoryByID(db *gorm.DB, id int) (Story, error) { var story Story err := db. @@ -48,17 +91,29 @@ func GetStoryByID(db *gorm.DB, id int) (Story, error) { } func CreateStory(db *gorm.DB, story *Story) error { - err := db. + // Check author's role + role, err := GetUserRoleByID(db, story.AuthorID) + if err != nil { + return fmt.Errorf("failed to get user role: %w", err) + } + + // Set story status based on author's role + if role == groupenums.RoleStandard { + story.Status = Draft + } else { + story.Status = Published + } + + // Create the story in the database + if err := db. Preload(clause.Associations). Create(story). - // Get associated Author. See - // https://github.com/go-gorm/gen/issues/618 on why - // a separate .First() is needed. + // Get associated Author. First(story). - Error - if err != nil { - return database.HandleDBError(err, "story") + Error; err != nil { + return fmt.Errorf("failed to create story: %w", err) } + return nil } @@ -88,7 +143,6 @@ func UpdateStory(db *gorm.DB, storyID int, newStory *Story) error { return database.HandleDBError(err, "story") } } - // Update remaining fields err = tx. Preload(clause.Associations). diff --git a/model/usergroups.go b/model/usergroups.go index 3bab68e..66cdb83 100644 --- a/model/usergroups.go +++ b/model/usergroups.go @@ -31,6 +31,21 @@ func GetUserGroupByID(db *gorm.DB, userID uint, groupID uint) (UserGroup, error) return userGroup, nil } +func GetUserRoleByID(db *gorm.DB, userID uint) (groupenums.Role, error) { + var userGroup UserGroup + + err := db.Model(&userGroup). + Where(UserGroup{UserID: userID}). + First(&userGroup).Error + + if err != nil { + return userGroup.Role, database.HandleDBError(err, "userRole") + } + + return userGroup.Role, nil +} + + func CreateUserGroup(db *gorm.DB, userGroup *UserGroup) error { err := db.Create(userGroup).Error if err != nil { diff --git a/params/stories/moderate.go b/params/stories/moderate.go new file mode 100644 index 0000000..e667c8e --- /dev/null +++ b/params/stories/moderate.go @@ -0,0 +1,28 @@ +package storyparams + +import ( + "github.com/source-academy/stories-backend/model" +) + +type Publish struct { + IsPublished bool `json:"boolean"` +} + +// Validate validates the Publish params. +func (params *Publish) Validate() error { + // Validation logic can be added here if needed. + return nil +} + +// ToModel converts Publish params to a Story model. +func (params *Publish) ToModel() *model.Story { + if (params.IsPublished) { + return &model.Story{ + Status: model.Published, + } + } else { + return &model.Story{ + Status: model.Draft, + } + } +} \ No newline at end of file From eeb21063146344ae0261a70d6205220e61da8f24 Mon Sep 17 00:00:00 2001 From: Kelly Wong Date: Wed, 20 Mar 2024 22:33:21 +0800 Subject: [PATCH 02/17] fixed GET published and draft stories --- model/stories.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/model/stories.go b/model/stories.go index bcade9e..aedb316 100644 --- a/model/stories.go +++ b/model/stories.go @@ -49,8 +49,8 @@ func GetAllStoriesInGroup(db *gorm.DB, groupID *uint) ([]Story, error) { func GetAllPublishedStories(db *gorm.DB, groupID *uint) ([]Story, error) { var stories []Story err := db. - // FIXME: Handle nil case properly - Where(Story{GroupID: groupID, Status: Published}). + Where("status = ?", int(Published)). + Where("group_id = ?", groupID). Preload(clause.Associations). // TODO: Abstract out the sorting logic Order("pin_order ASC NULLS LAST, title ASC, content ASC"). @@ -65,8 +65,8 @@ func GetAllPublishedStories(db *gorm.DB, groupID *uint) ([]Story, error) { func GetAllDraftStories(db *gorm.DB, groupID *uint) ([]Story, error) { var stories []Story err := db. - // FIXME: Handle nil case properly - Where(Story{GroupID: groupID, Status: Draft}). + Where("status = ?", int(Draft)). + Where("group_id = ?", groupID). Preload(clause.Associations). // TODO: Abstract out the sorting logic Order("pin_order ASC NULLS LAST, title ASC, content ASC"). From a681b9602fd4f204a60d52f674b664cae4e9b371 Mon Sep 17 00:00:00 2001 From: Kelly Wong Date: Wed, 20 Mar 2024 22:52:46 +0800 Subject: [PATCH 03/17] fixed merge conflicts 2 --- go.sum | 102 ----------------------------------------------- model/stories.go | 3 -- 2 files changed, 105 deletions(-) diff --git a/go.sum b/go.sum index 7976614..e87f6f9 100644 --- a/go.sum +++ b/go.sum @@ -44,16 +44,9 @@ github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= -<<<<<<< HEAD -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -======= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= ->>>>>>> main github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= @@ -102,81 +95,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -<<<<<<< HEAD -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -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/zmb3/gogetdoc v0.0.0-20190228002656-b37376c5da6a h1:00UFliGZl2UciXe8o/2iuEsRQ9u7z0rzDTVzuj6EYY0= -github.com/zmb3/gogetdoc v0.0.0-20190228002656-b37376c5da6a/go.mod h1:ofmGw6LrMypycsiWcyug6516EXpIxSbZ+uI9ppGypfY= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338 h1:2O2DON6y3XMJiQRAS1UWU+54aec2uopH3x7MAiqGW6Y= -golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -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-20220412211240-33da011f77ad/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/telemetry v0.0.0-20231114163143-69313e640400 h1:brbkEFfGwNGAEkykUOcryE/JiHUMMJouzE0fWWmz/QU= -golang.org/x/telemetry v0.0.0-20231114163143-69313e640400/go.mod h1:P6hMdmAcoG7FyATwqSr6R/U0n7yeXNP/QXeRlxb1szE= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181207195948-8634b1ecd393/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -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/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.14.1-0.20231114185516-c9d3e7de13fd h1:Oku7E+OCrXHyst1dG1z10etCTxewCHXNFLRlyMPbh3w= -golang.org/x/tools v0.14.1-0.20231114185516-c9d3e7de13fd/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools/gopls v0.14.2 h1:sIw6vjZiuQ9S7s0auUUkHlWgsCkKZFWDHmrge8LYsnc= -golang.org/x/tools/gopls v0.14.2/go.mod h1:o2s+suLlFye+MHxEofsxJPkBQ/kT/ucP4iJV3ohjGEQ= -golang.org/x/vuln v1.0.1 h1:KUas02EjQK5LTuIx1OylBQdKKZ9jeugs+HiqO5HormU= -golang.org/x/vuln v1.0.1/go.mod h1:bb2hMwln/tqxg32BNY4CcxHWtHXuYa3SbIBmtsyjxtM= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -======= 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= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= @@ -190,29 +108,10 @@ 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/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= ->>>>>>> main gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -<<<<<<< HEAD -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -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= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= -gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= -gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= -gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -honnef.co/go/tools v0.4.5 h1:YGD4H+SuIOOqsyoLOpZDWcieM28W47/zRO7f+9V3nvo= -honnef.co/go/tools v0.4.5/go.mod h1:GUV+uIBCLpdf0/v6UhHHG/yzI/z6qPskBeQCjcNB96k= -mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM= -mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= -mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc= -mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg= -======= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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= @@ -221,4 +120,3 @@ gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo= gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0= gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= ->>>>>>> main diff --git a/model/stories.go b/model/stories.go index 6695099..0f08f56 100644 --- a/model/stories.go +++ b/model/stories.go @@ -1,10 +1,7 @@ package model import ( - "fmt" - "github.com/source-academy/stories-backend/internal/database" - groupenums "github.com/source-academy/stories-backend/internal/enums/groups" "gorm.io/gorm" "gorm.io/gorm/clause" ) From 2844a8916ae367a776c668b1821dfc091692cb02 Mon Sep 17 00:00:00 2001 From: keyansheng <65121402+keyansheng@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:59:15 +0800 Subject: [PATCH 04/17] Run make format Running pre-commit hook... Go code is not formatted, commit blocked! The following files are not formatted: ./controller/stories/update.go ./internal/auth/middleware.go ./internal/permissions/users/permissions.go ./internal/permissions/users/role.go ./internal/router/router.go ./model/stories.go ./model/usergroups.go ./params/stories/moderate.go Run 'make format' to format your files and try again. --- controller/stories/update.go | 2 +- internal/auth/middleware.go | 6 +++--- internal/permissions/users/permissions.go | 8 ++++---- internal/permissions/users/role.go | 2 -- internal/router/router.go | 2 +- model/stories.go | 22 +++++++++++----------- model/usergroups.go | 17 ++++++++--------- params/stories/moderate.go | 12 ++++++------ 8 files changed, 34 insertions(+), 37 deletions(-) diff --git a/controller/stories/update.go b/controller/stories/update.go index 61dda32..6988f75 100644 --- a/controller/stories/update.go +++ b/controller/stories/update.go @@ -146,4 +146,4 @@ func HandlePublish(w http.ResponseWriter, r *http.Request) error { controller.EncodeJSONResponse(w, storyviews.SingleFrom(storyModel)) return nil -} \ No newline at end of file +} diff --git a/internal/auth/middleware.go b/internal/auth/middleware.go index 85e01db..44317d8 100644 --- a/internal/auth/middleware.go +++ b/internal/auth/middleware.go @@ -29,10 +29,10 @@ func MakeMiddlewareFrom(conf *config.Config) func(http.Handler) http.Handler { if conf.Environment == envutils.ENV_DEVELOPMENT { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - r = injectUserIDToContext(r, 1) - next.ServeHTTP(w, r) + r = injectUserIDToContext(r, 1) + next.ServeHTTP(w, r) }) - } + } } keySet := getJWKS(conf.JWKSEndpoint) diff --git a/internal/permissions/users/permissions.go b/internal/permissions/users/permissions.go index a5673bb..9cb276d 100644 --- a/internal/permissions/users/permissions.go +++ b/internal/permissions/users/permissions.go @@ -13,9 +13,9 @@ const ( CanUpdateGroups Permission = "can_update_groups" CanDeleteGroups Permission = "can_delete_groups" - CanCreateStories Permission = "can_create_stories" - CanReadStories Permission = "can_read_stories" - CanUpdateStories Permission = "can_update_stories" - CanDeleteStories Permission = "can_delete_stories" + CanCreateStories Permission = "can_create_stories" + CanReadStories Permission = "can_read_stories" + CanUpdateStories Permission = "can_update_stories" + CanDeleteStories Permission = "can_delete_stories" CanPublishStories Permission = "can_publish_stories" ) diff --git a/internal/permissions/users/role.go b/internal/permissions/users/role.go index 0e0c7c4..c0dccc7 100644 --- a/internal/permissions/users/role.go +++ b/internal/permissions/users/role.go @@ -19,5 +19,3 @@ func (p RolePermission) IsAuthorized(r *http.Request) bool { } return groupenums.IsRoleGreaterThan(*role, p.Role) } - - diff --git a/internal/router/router.go b/internal/router/router.go index 9103f30..e6b1d91 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -62,7 +62,7 @@ func Setup(config *config.Config, injectMiddleWares []func(http.Handler) http.Ha r.Put("/{storyID}/publish", handleAPIError(stories.HandlePublish)) r.Delete("/{storyID}", handleAPIError(stories.HandleDelete)) r.Post("/", handleAPIError(stories.HandleCreate)) - }) + }) r.Route("/users", func(r chi.Router) { r.Get("/", handleAPIError(users.HandleList)) diff --git a/model/stories.go b/model/stories.go index 0f08f56..c44bb69 100644 --- a/model/stories.go +++ b/model/stories.go @@ -9,20 +9,20 @@ import ( type StoryStatus int const ( - Draft StoryStatus = iota - Published + Draft StoryStatus = iota + Published ) type Story struct { - gorm.Model - AuthorID uint - Author User - GroupID *uint - Group Group - Title string - Content string - PinOrder *int - Status StoryStatus + gorm.Model + AuthorID uint + Author User + GroupID *uint + Group Group + Title string + Content string + PinOrder *int + Status StoryStatus } // Passing nil to omit the filtering and get all stories diff --git a/model/usergroups.go b/model/usergroups.go index 66cdb83..d40a9ea 100644 --- a/model/usergroups.go +++ b/model/usergroups.go @@ -32,20 +32,19 @@ func GetUserGroupByID(db *gorm.DB, userID uint, groupID uint) (UserGroup, error) } func GetUserRoleByID(db *gorm.DB, userID uint) (groupenums.Role, error) { - var userGroup UserGroup + var userGroup UserGroup - err := db.Model(&userGroup). - Where(UserGroup{UserID: userID}). - First(&userGroup).Error + err := db.Model(&userGroup). + Where(UserGroup{UserID: userID}). + First(&userGroup).Error - if err != nil { - return userGroup.Role, database.HandleDBError(err, "userRole") - } + if err != nil { + return userGroup.Role, database.HandleDBError(err, "userRole") + } - return userGroup.Role, nil + return userGroup.Role, nil } - func CreateUserGroup(db *gorm.DB, userGroup *UserGroup) error { err := db.Create(userGroup).Error if err != nil { diff --git a/params/stories/moderate.go b/params/stories/moderate.go index e667c8e..1008724 100644 --- a/params/stories/moderate.go +++ b/params/stories/moderate.go @@ -1,22 +1,22 @@ package storyparams import ( - "github.com/source-academy/stories-backend/model" + "github.com/source-academy/stories-backend/model" ) type Publish struct { - IsPublished bool `json:"boolean"` + IsPublished bool `json:"boolean"` } // Validate validates the Publish params. func (params *Publish) Validate() error { - // Validation logic can be added here if needed. - return nil + // Validation logic can be added here if needed. + return nil } // ToModel converts Publish params to a Story model. func (params *Publish) ToModel() *model.Story { - if (params.IsPublished) { + if params.IsPublished { return &model.Story{ Status: model.Published, } @@ -25,4 +25,4 @@ func (params *Publish) ToModel() *model.Story { Status: model.Draft, } } -} \ No newline at end of file +} From 622bc5a2169b87fc011ac924752b77fd7910edf5 Mon Sep 17 00:00:00 2001 From: keyansheng <65121402+keyansheng@users.noreply.github.com> Date: Wed, 20 Mar 2024 23:08:22 +0800 Subject: [PATCH 05/17] Restore .env.example --- .env.example | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..042807b --- /dev/null +++ b/.env.example @@ -0,0 +1,18 @@ +HOST=localhost +PORT=8080 + +DB_TIMEZONE=Asia/Singapore +DB_HOSTNAME=localhost +DB_PORT=5432 +DB_USERNAME=postgres +DB_PASSWORD= +DB_NAME= + +SENTRY_DSN= + +JWKS_ENDPOINT= + +# only for non-development mode +ALLOWED_ORIGIN_1= +ALLOWED_ORIGIN_2= +# ... and so on From feeb54027a5ce8576ee127a2a2789f7137a72124 Mon Sep 17 00:00:00 2001 From: Kelly Wong Date: Wed, 20 Mar 2024 23:09:19 +0800 Subject: [PATCH 06/17] fix formatting --- controller/stories/update.go | 2 +- internal/auth/middleware.go | 6 +++--- internal/permissions/users/permissions.go | 8 ++++---- internal/permissions/users/role.go | 2 -- internal/router/router.go | 2 +- model/stories.go | 22 +++++++++++----------- model/usergroups.go | 17 ++++++++--------- params/stories/moderate.go | 12 ++++++------ 8 files changed, 34 insertions(+), 37 deletions(-) diff --git a/controller/stories/update.go b/controller/stories/update.go index 61dda32..6988f75 100644 --- a/controller/stories/update.go +++ b/controller/stories/update.go @@ -146,4 +146,4 @@ func HandlePublish(w http.ResponseWriter, r *http.Request) error { controller.EncodeJSONResponse(w, storyviews.SingleFrom(storyModel)) return nil -} \ No newline at end of file +} diff --git a/internal/auth/middleware.go b/internal/auth/middleware.go index 85e01db..44317d8 100644 --- a/internal/auth/middleware.go +++ b/internal/auth/middleware.go @@ -29,10 +29,10 @@ func MakeMiddlewareFrom(conf *config.Config) func(http.Handler) http.Handler { if conf.Environment == envutils.ENV_DEVELOPMENT { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - r = injectUserIDToContext(r, 1) - next.ServeHTTP(w, r) + r = injectUserIDToContext(r, 1) + next.ServeHTTP(w, r) }) - } + } } keySet := getJWKS(conf.JWKSEndpoint) diff --git a/internal/permissions/users/permissions.go b/internal/permissions/users/permissions.go index a5673bb..9cb276d 100644 --- a/internal/permissions/users/permissions.go +++ b/internal/permissions/users/permissions.go @@ -13,9 +13,9 @@ const ( CanUpdateGroups Permission = "can_update_groups" CanDeleteGroups Permission = "can_delete_groups" - CanCreateStories Permission = "can_create_stories" - CanReadStories Permission = "can_read_stories" - CanUpdateStories Permission = "can_update_stories" - CanDeleteStories Permission = "can_delete_stories" + CanCreateStories Permission = "can_create_stories" + CanReadStories Permission = "can_read_stories" + CanUpdateStories Permission = "can_update_stories" + CanDeleteStories Permission = "can_delete_stories" CanPublishStories Permission = "can_publish_stories" ) diff --git a/internal/permissions/users/role.go b/internal/permissions/users/role.go index 0e0c7c4..c0dccc7 100644 --- a/internal/permissions/users/role.go +++ b/internal/permissions/users/role.go @@ -19,5 +19,3 @@ func (p RolePermission) IsAuthorized(r *http.Request) bool { } return groupenums.IsRoleGreaterThan(*role, p.Role) } - - diff --git a/internal/router/router.go b/internal/router/router.go index 9103f30..e6b1d91 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -62,7 +62,7 @@ func Setup(config *config.Config, injectMiddleWares []func(http.Handler) http.Ha r.Put("/{storyID}/publish", handleAPIError(stories.HandlePublish)) r.Delete("/{storyID}", handleAPIError(stories.HandleDelete)) r.Post("/", handleAPIError(stories.HandleCreate)) - }) + }) r.Route("/users", func(r chi.Router) { r.Get("/", handleAPIError(users.HandleList)) diff --git a/model/stories.go b/model/stories.go index 0f08f56..c44bb69 100644 --- a/model/stories.go +++ b/model/stories.go @@ -9,20 +9,20 @@ import ( type StoryStatus int const ( - Draft StoryStatus = iota - Published + Draft StoryStatus = iota + Published ) type Story struct { - gorm.Model - AuthorID uint - Author User - GroupID *uint - Group Group - Title string - Content string - PinOrder *int - Status StoryStatus + gorm.Model + AuthorID uint + Author User + GroupID *uint + Group Group + Title string + Content string + PinOrder *int + Status StoryStatus } // Passing nil to omit the filtering and get all stories diff --git a/model/usergroups.go b/model/usergroups.go index 66cdb83..d40a9ea 100644 --- a/model/usergroups.go +++ b/model/usergroups.go @@ -32,20 +32,19 @@ func GetUserGroupByID(db *gorm.DB, userID uint, groupID uint) (UserGroup, error) } func GetUserRoleByID(db *gorm.DB, userID uint) (groupenums.Role, error) { - var userGroup UserGroup + var userGroup UserGroup - err := db.Model(&userGroup). - Where(UserGroup{UserID: userID}). - First(&userGroup).Error + err := db.Model(&userGroup). + Where(UserGroup{UserID: userID}). + First(&userGroup).Error - if err != nil { - return userGroup.Role, database.HandleDBError(err, "userRole") - } + if err != nil { + return userGroup.Role, database.HandleDBError(err, "userRole") + } - return userGroup.Role, nil + return userGroup.Role, nil } - func CreateUserGroup(db *gorm.DB, userGroup *UserGroup) error { err := db.Create(userGroup).Error if err != nil { diff --git a/params/stories/moderate.go b/params/stories/moderate.go index e667c8e..1008724 100644 --- a/params/stories/moderate.go +++ b/params/stories/moderate.go @@ -1,22 +1,22 @@ package storyparams import ( - "github.com/source-academy/stories-backend/model" + "github.com/source-academy/stories-backend/model" ) type Publish struct { - IsPublished bool `json:"boolean"` + IsPublished bool `json:"boolean"` } // Validate validates the Publish params. func (params *Publish) Validate() error { - // Validation logic can be added here if needed. - return nil + // Validation logic can be added here if needed. + return nil } // ToModel converts Publish params to a Story model. func (params *Publish) ToModel() *model.Story { - if (params.IsPublished) { + if params.IsPublished { return &model.Story{ Status: model.Published, } @@ -25,4 +25,4 @@ func (params *Publish) ToModel() *model.Story { Status: model.Draft, } } -} \ No newline at end of file +} From 43ab0dda3aae829bf9de3c1da44ea6f83c82c1fa Mon Sep 17 00:00:00 2001 From: Kelly Wong Date: Wed, 20 Mar 2024 23:26:09 +0800 Subject: [PATCH 07/17] fix formatting --- go.sum | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/go.sum b/go.sum index e87f6f9..a63ae4c 100644 --- a/go.sum +++ b/go.sum @@ -45,8 +45,11 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= @@ -73,12 +76,14 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6 github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rubenv/sql-migrate v1.5.1 h1:WsZo4jPQfjmddDTh/suANP2aKPA7/ekN0LzuuajgQEo= @@ -99,6 +104,7 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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/sync v0.0.0-20210220032951-036812b2e83c/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/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -108,11 +114,15 @@ 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/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools/gopls v0.14.2/go.mod h1:o2s+suLlFye+MHxEofsxJPkBQ/kT/ucP4iJV3ohjGEQ= +golang.org/x/vuln v1.0.1/go.mod h1:bb2hMwln/tqxg32BNY4CcxHWtHXuYa3SbIBmtsyjxtM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -120,3 +130,6 @@ gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo= gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0= gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +honnef.co/go/tools v0.4.5/go.mod h1:GUV+uIBCLpdf0/v6UhHHG/yzI/z6qPskBeQCjcNB96k= +mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= +mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg= From fbd5342912fab705f1540860b28c3316b335ae3c Mon Sep 17 00:00:00 2001 From: keyansheng <65121402+keyansheng@users.noreply.github.com> Date: Wed, 27 Mar 2024 00:13:19 +0800 Subject: [PATCH 08/17] Run go get --- go.sum | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/go.sum b/go.sum index e87f6f9..a63ae4c 100644 --- a/go.sum +++ b/go.sum @@ -45,8 +45,11 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= @@ -73,12 +76,14 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6 github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rubenv/sql-migrate v1.5.1 h1:WsZo4jPQfjmddDTh/suANP2aKPA7/ekN0LzuuajgQEo= @@ -99,6 +104,7 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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/sync v0.0.0-20210220032951-036812b2e83c/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/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -108,11 +114,15 @@ 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/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools/gopls v0.14.2/go.mod h1:o2s+suLlFye+MHxEofsxJPkBQ/kT/ucP4iJV3ohjGEQ= +golang.org/x/vuln v1.0.1/go.mod h1:bb2hMwln/tqxg32BNY4CcxHWtHXuYa3SbIBmtsyjxtM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -120,3 +130,6 @@ gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo= gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0= gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +honnef.co/go/tools v0.4.5/go.mod h1:GUV+uIBCLpdf0/v6UhHHG/yzI/z6qPskBeQCjcNB96k= +mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= +mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg= From 2efef3ffff5193863aa5d7b549e39ac76e7ccb62 Mon Sep 17 00:00:00 2001 From: keyansheng <65121402+keyansheng@users.noreply.github.com> Date: Wed, 27 Mar 2024 00:32:02 +0800 Subject: [PATCH 09/17] Fix migration ordering --- ...0230807190030-add_status.sql => 20240320000000-add_status.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename migrations/{20230807190030-add_status.sql => 20240320000000-add_status.sql} (100%) diff --git a/migrations/20230807190030-add_status.sql b/migrations/20240320000000-add_status.sql similarity index 100% rename from migrations/20230807190030-add_status.sql rename to migrations/20240320000000-add_status.sql From ef9b9317df2155a6d313ed6f6b4417c5eb6fad4f Mon Sep 17 00:00:00 2001 From: Kelly Wong Date: Wed, 27 Mar 2024 01:58:12 +0800 Subject: [PATCH 10/17] moderation draft 1 --- controller/stories/stories.go | 83 ++++++++++++++++++-- controller/stories/update.go | 62 --------------- internal/permissiongroups/stories/stories.go | 4 +- internal/permissions/users/permissions.go | 10 +-- internal/permissions/users/users.go | 2 +- internal/router/router.go | 3 +- migrations/20230807190031-add_status.sql | 9 +++ model/stories.go | 75 +++++++++++++++--- params/stories/moderate.go | 28 ------- params/stories/update.go | 16 ++-- 10 files changed, 170 insertions(+), 122 deletions(-) create mode 100644 migrations/20230807190031-add_status.sql delete mode 100644 params/stories/moderate.go diff --git a/controller/stories/stories.go b/controller/stories/stories.go index 4453614..0e0965b 100644 --- a/controller/stories/stories.go +++ b/controller/stories/stories.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "net/http" - "strconv" "github.com/go-chi/chi/v5" @@ -59,7 +58,40 @@ func HandleListPublished(w http.ResponseWriter, r *http.Request) error { if err != nil { logrus.Error(err) return apierrors.ClientForbiddenError{ - Message: fmt.Sprintf("Error listing stories: %v", err), + Message: fmt.Sprintf("Error listing published stories: %v", err), + } + } + + // Get DB instance + db, err := database.GetDBFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + // Get group id from context + groupID, err := usergroups.GetGroupIDFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + stories, err := model.GetAllStoriesByStatus(db, groupID, model.Published) + if err != nil { + logrus.Error(err) + return err + } + + controller.EncodeJSONResponse(w, storyviews.ListFrom(stories)) + return nil +} + +func HandleListPending(w http.ResponseWriter, r *http.Request) error { + err := auth.CheckPermissions(r, storypermissiongroups.Moderate()) + if err != nil { + logrus.Error(err) + return apierrors.ClientForbiddenError{ + Message: fmt.Sprintf("Error listing stories to be reviewed: %v", err), } } @@ -77,7 +109,7 @@ func HandleListPublished(w http.ResponseWriter, r *http.Request) error { return err } - stories, err := model.GetAllPublishedStories(db, groupID) + stories, err := model.GetAllStoriesByStatus(db, groupID, model.Pending) if err != nil { logrus.Error(err) return err @@ -92,10 +124,51 @@ func HandleListDraft(w http.ResponseWriter, r *http.Request) error { if err != nil { logrus.Error(err) return apierrors.ClientForbiddenError{ - Message: fmt.Sprintf("Error listing stories: %v", err), + Message: fmt.Sprintf("Error listing drafts: %v", err), } } + userID, err := auth.GetUserIDFrom(r) + if err != nil { + logrus.Error(err) + return err + } + // Get DB instance + db, err := database.GetDBFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + // Get group id from context + groupID, err := usergroups.GetGroupIDFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + stories, err := model.GetAllAuthorStoriesByStatus(db, groupID, userID, model.Draft) + if err != nil { + logrus.Error(err) + return err + } + controller.EncodeJSONResponse(w, storyviews.ListFrom(stories)) + return nil +} + +func HandleListRejected(w http.ResponseWriter, r *http.Request) error { + err := auth.CheckPermissions(r, storypermissiongroups.List()) + if err != nil { + logrus.Error(err) + return apierrors.ClientForbiddenError{ + Message: fmt.Sprintf("Error listing rejected stories: %v", err), + } + } + userID, err := auth.GetUserIDFrom(r) + if err != nil { + logrus.Error(err) + return err + } // Get DB instance db, err := database.GetDBFrom(r) if err != nil { @@ -110,7 +183,7 @@ func HandleListDraft(w http.ResponseWriter, r *http.Request) error { return err } - stories, err := model.GetAllDraftStories(db, groupID) + stories, err := model.GetAllAuthorStoriesByStatus(db, groupID, userID, model.Rejected) if err != nil { logrus.Error(err) return err diff --git a/controller/stories/update.go b/controller/stories/update.go index 6988f75..3079e67 100644 --- a/controller/stories/update.go +++ b/controller/stories/update.go @@ -85,65 +85,3 @@ func HandleUpdate(w http.ResponseWriter, r *http.Request) error { controller.EncodeJSONResponse(w, storyviews.SingleFrom(storyModel)) return nil } - -func HandlePublish(w http.ResponseWriter, r *http.Request) error { - storyIDStr := chi.URLParam(r, "storyID") - storyID, err := strconv.Atoi(storyIDStr) - if err != nil { - return apierrors.ClientBadRequestError{ - Message: fmt.Sprintf("Invalid storyID: %v", err), - } - } - - err = auth.CheckPermissions(r, storypermissiongroups.Publish()) - if err != nil { - logrus.Error(err) - return apierrors.ClientForbiddenError{ - Message: fmt.Sprintf("Error moderating story: %v", err), - } - } - - // Extra params won't do anything, e.g. authorID can't be changed. - // TODO: Error on extra params? - var params storyparams.Update - if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { - e, ok := err.(*json.UnmarshalTypeError) - if !ok { - logrus.Error(err) - return apierrors.ClientBadRequestError{ - Message: fmt.Sprintf("Bad JSON parsing: %v", err), - } - } - - // TODO: Investigate if we should use errors.Wrap instead - return apierrors.ClientUnprocessableEntityError{ - Message: fmt.Sprintf("Invalid JSON format: %s should be a %s.", e.Field, e.Type), - } - } - - err = params.Validate() - if err != nil { - logrus.Error(err) - return apierrors.ClientUnprocessableEntityError{ - Message: fmt.Sprintf("JSON validation failed: %v", err), - } - } - - storyModel := *params.ToModel() - - // Get DB instance - db, err := database.GetDBFrom(r) - if err != nil { - logrus.Error(err) - return err - } - - err = model.UpdateStory(db, storyID, &storyModel) - if err != nil { - logrus.Error(err) - return err - } - - controller.EncodeJSONResponse(w, storyviews.SingleFrom(storyModel)) - return nil -} diff --git a/internal/permissiongroups/stories/stories.go b/internal/permissiongroups/stories/stories.go index 5d38811..039f753 100644 --- a/internal/permissiongroups/stories/stories.go +++ b/internal/permissiongroups/stories/stories.go @@ -20,9 +20,9 @@ func Read() permissions.PermissionGroup { GetRolePermission(userpermissions.CanReadStories) } -func Publish() permissions.PermissionGroup { +func Moderate() permissions.PermissionGroup { return userpermissions. - GetRolePermission(userpermissions.CanPublishStories) + GetRolePermission(userpermissions.CanModerateStories) } func Update(storyID uint) permissions.PermissionGroup { diff --git a/internal/permissions/users/permissions.go b/internal/permissions/users/permissions.go index 9cb276d..0aa325b 100644 --- a/internal/permissions/users/permissions.go +++ b/internal/permissions/users/permissions.go @@ -13,9 +13,9 @@ const ( CanUpdateGroups Permission = "can_update_groups" CanDeleteGroups Permission = "can_delete_groups" - CanCreateStories Permission = "can_create_stories" - CanReadStories Permission = "can_read_stories" - CanUpdateStories Permission = "can_update_stories" - CanDeleteStories Permission = "can_delete_stories" - CanPublishStories Permission = "can_publish_stories" + CanCreateStories Permission = "can_create_stories" + CanReadStories Permission = "can_read_stories" + CanUpdateStories Permission = "can_update_stories" + CanDeleteStories Permission = "can_delete_stories" + CanModerateStories Permission = "can_moderate_stories" ) diff --git a/internal/permissions/users/users.go b/internal/permissions/users/users.go index d4c4992..e330ced 100644 --- a/internal/permissions/users/users.go +++ b/internal/permissions/users/users.go @@ -23,7 +23,7 @@ func GetRolePermission(p Permission) *RolePermission { case // Additional permissions for moderators and administrators CanUpdateStories, - CanPublishStories, + CanModerateStories, CanDeleteStories: return &RolePermission{ Permission: p, diff --git a/internal/router/router.go b/internal/router/router.go index e6b1d91..d86a904 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -56,10 +56,11 @@ func Setup(config *config.Config, injectMiddleWares []func(http.Handler) http.Ha r.Route("/stories", func(r chi.Router) { r.Get("/", handleAPIError(stories.HandleList)) r.Get("/draft", handleAPIError(stories.HandleListDraft)) + r.Get("/pending", handleAPIError(stories.HandleListPending)) r.Get("/published", handleAPIError(stories.HandleListPublished)) + r.Get("/rejected", handleAPIError(stories.HandleListPublished)) r.Get("/{storyID}", handleAPIError(stories.HandleRead)) r.Put("/{storyID}", handleAPIError(stories.HandleUpdate)) - r.Put("/{storyID}/publish", handleAPIError(stories.HandlePublish)) r.Delete("/{storyID}", handleAPIError(stories.HandleDelete)) r.Post("/", handleAPIError(stories.HandleCreate)) }) diff --git a/migrations/20230807190031-add_status.sql b/migrations/20230807190031-add_status.sql new file mode 100644 index 0000000..821694e --- /dev/null +++ b/migrations/20230807190031-add_status.sql @@ -0,0 +1,9 @@ +-- +migrate Up + +ALTER TABLE stories + ADD COLUMN status_message TEXT; + +-- +migrate Down + +ALTER TABLE stories + DROP COLUMN status_message; \ No newline at end of file diff --git a/model/stories.go b/model/stories.go index c44bb69..fcb4933 100644 --- a/model/stories.go +++ b/model/stories.go @@ -2,6 +2,7 @@ package model import ( "github.com/source-academy/stories-backend/internal/database" + groupenums "github.com/source-academy/stories-backend/internal/enums/groups" "gorm.io/gorm" "gorm.io/gorm/clause" ) @@ -10,19 +11,22 @@ type StoryStatus int const ( Draft StoryStatus = iota + Pending + Rejected Published ) type Story struct { gorm.Model - AuthorID uint - Author User - GroupID *uint - Group Group - Title string - Content string - PinOrder *int - Status StoryStatus + AuthorID uint + Author User + GroupID *uint + Group Group + Title string + Content string + PinOrder *int + Status StoryStatus + StatusMessage *string } // Passing nil to omit the filtering and get all stories @@ -59,10 +63,10 @@ func GetAllPublishedStories(db *gorm.DB, groupID *uint) ([]Story, error) { return stories, nil } -func GetAllDraftStories(db *gorm.DB, groupID *uint) ([]Story, error) { +func GetAllPendingStories(db *gorm.DB, groupID *uint) ([]Story, error) { var stories []Story err := db. - Where("status = ?", int(Draft)). + Where("status = ?", int(Pending)). Where("group_id = ?", groupID). Preload(clause.Associations). // TODO: Abstract out the sorting logic @@ -75,6 +79,39 @@ func GetAllDraftStories(db *gorm.DB, groupID *uint) ([]Story, error) { return stories, nil } +func GetAllStoriesByStatus(db *gorm.DB, groupID *uint, status StoryStatus) ([]Story, error) { + var stories []Story + err := db. + Where("status = ?", int(status)). + Where("group_id = ?", groupID). + Preload(clause.Associations). + // TODO: Abstract out the sorting logic + Order("pin_order ASC NULLS LAST, title ASC, content ASC"). + Find(&stories). + Error + if err != nil { + return stories, database.HandleDBError(err, "story") + } + return stories, nil +} + +func GetAllAuthorStoriesByStatus(db *gorm.DB, groupID *uint, userID *int, status StoryStatus) ([]Story, error) { + var stories []Story + err := db. + Where("status = ?", int(status)). + Where("group_id = ?", groupID). + Where("author_id = ?", userID). + Preload(clause.Associations). + // TODO: Abstract out the sorting logic + Order("pin_order ASC NULLS LAST, title ASC, content ASC"). + Find(&stories). + Error + if err != nil { + return stories, database.HandleDBError(err, "story") + } + return stories, nil +} + func GetStoryByID(db *gorm.DB, id int) (Story, error) { var story Story err := db. @@ -98,8 +135,22 @@ func (s *Story) create(tx *gorm.DB) *gorm.DB { } func CreateStory(db *gorm.DB, story *Story) error { - err := db.Transaction(func(tx *gorm.DB) error { - return story.create(tx).Error + // Check author's role + role, err := GetUserRoleByID(db, story.AuthorID) + if err != nil { + return database.HandleDBError(err, "userRole") + } + // Set story status based on author's role + if role == groupenums.RoleStandard { + story.Status = Draft + } else { + story.Status = Published + } + err = db.Transaction(func(tx *gorm.DB) error { + if err := tx.Create(story).Error; err != nil { + return err // Return the error directly + } + return nil }) if err != nil { return database.HandleDBError(err, "story") diff --git a/params/stories/moderate.go b/params/stories/moderate.go deleted file mode 100644 index 1008724..0000000 --- a/params/stories/moderate.go +++ /dev/null @@ -1,28 +0,0 @@ -package storyparams - -import ( - "github.com/source-academy/stories-backend/model" -) - -type Publish struct { - IsPublished bool `json:"boolean"` -} - -// Validate validates the Publish params. -func (params *Publish) Validate() error { - // Validation logic can be added here if needed. - return nil -} - -// ToModel converts Publish params to a Story model. -func (params *Publish) ToModel() *model.Story { - if params.IsPublished { - return &model.Story{ - Status: model.Published, - } - } else { - return &model.Story{ - Status: model.Draft, - } - } -} diff --git a/params/stories/update.go b/params/stories/update.go index 8eb14fe..be49751 100644 --- a/params/stories/update.go +++ b/params/stories/update.go @@ -5,9 +5,11 @@ import ( ) type Update struct { - Title string `json:"title"` - Content string `json:"content"` - PinOrder *int `json:"pinOrder"` + Title string `json:"title"` + Content string `json:"content"` + PinOrder *int `json:"pinOrder"` + Status int `json:"status"` + StatusMessage string `json:"statusMessage"` } func (params *Update) Validate() error { @@ -18,8 +20,10 @@ func (params *Update) Validate() error { func (params *Update) ToModel() *model.Story { return &model.Story{ - Title: params.Title, - Content: params.Content, - PinOrder: params.PinOrder, + Title: params.Title, + Content: params.Content, + PinOrder: params.PinOrder, + Status: model.StoryStatus(params.Status), + StatusMessage: ¶ms.StatusMessage, } } From 0e3491eb7bad48401b900457a2387468b08598b0 Mon Sep 17 00:00:00 2001 From: Kelly Wong Date: Wed, 27 Mar 2024 02:27:59 +0800 Subject: [PATCH 11/17] add validation for create story, added unit test for it --- params/stories/create.go | 13 +++++++++++++ params/stories/create_test.go | 22 +++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/params/stories/create.go b/params/stories/create.go index 3e8bf80..cc101d5 100644 --- a/params/stories/create.go +++ b/params/stories/create.go @@ -1,6 +1,7 @@ package storyparams import ( + "fmt" "github.com/source-academy/stories-backend/model" ) @@ -13,6 +14,18 @@ type Create struct { // TODO: Add some validation func (params *Create) Validate() error { + if params.AuthorID == 0 { + return fmt.Errorf("authorId is required and must be non-zero") + } + if params.Title == "" { + return fmt.Errorf("title is required and cannot be empty") + } + if params.Content == "" { + return fmt.Errorf("content is required and cannot be empty") + } + if params.PinOrder != nil && *params.PinOrder < 0 { + return fmt.Errorf("pinOrder, if set, must be non-negative") + } return nil } diff --git a/params/stories/create_test.go b/params/stories/create_test.go index f100c4d..8975470 100644 --- a/params/stories/create_test.go +++ b/params/stories/create_test.go @@ -7,7 +7,27 @@ import ( ) func TestValidate(t *testing.T) { - t.Run("should do nothing for now", func(t *testing.T) {}) + negativePinOrder := -1 + tests := []struct { + name string + params Create + wantErr bool + }{ + {"valid input", Create{AuthorID: 1, Title: "Test Title", Content: "Test Content"}, false}, + {"missing authorId", Create{Title: "Test Title", Content: "Test Content"}, true}, + {"empty title", Create{AuthorID: 1, Content: "Test Content"}, true}, + {"empty content", Create{AuthorID: 1, Title: "Test Title"}, true}, + {"negative pinOrder", Create{AuthorID: 1, Title: "Test Title", Content: "Test Content", PinOrder: &negativePinOrder}, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.params.Validate() + if (err != nil) != tt.wantErr { + t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } } func TestToModel(t *testing.T) { From e54b1ecac7b84a1700914cc1cfcd64f803707808 Mon Sep 17 00:00:00 2001 From: keyansheng <65121402+keyansheng@users.noreply.github.com> Date: Wed, 27 Mar 2024 04:13:05 +0800 Subject: [PATCH 12/17] Fix TestCreateStory/can_create_without_group fail --- model/stories.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/model/stories.go b/model/stories.go index fcb4933..f192d38 100644 --- a/model/stories.go +++ b/model/stories.go @@ -136,17 +136,16 @@ func (s *Story) create(tx *gorm.DB) *gorm.DB { func CreateStory(db *gorm.DB, story *Story) error { // Check author's role - role, err := GetUserRoleByID(db, story.AuthorID) - if err != nil { - return database.HandleDBError(err, "userRole") - } + role, _ := GetUserRoleByID(db, story.AuthorID) + // Based on the TestCreateStory, "can create without group" seems to be the desired behaviour + // No group means no userGroup, which means no role, so an error shouldn't be thrown // Set story status based on author's role - if role == groupenums.RoleStandard { + if !groupenums.IsRoleGreaterThan(role, groupenums.RoleStandard) { story.Status = Draft } else { story.Status = Published } - err = db.Transaction(func(tx *gorm.DB) error { + err := db.Transaction(func(tx *gorm.DB) error { if err := tx.Create(story).Error; err != nil { return err // Return the error directly } From 0b49dd967d3608c6d7d21ef8a4973c9c6198f837 Mon Sep 17 00:00:00 2001 From: keyansheng <65121402+keyansheng@users.noreply.github.com> Date: Wed, 27 Mar 2024 04:22:33 +0800 Subject: [PATCH 13/17] Fix migration ordering --- ...0230807190031-add_status.sql => 20240320000001-add_status.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename migrations/{20230807190031-add_status.sql => 20240320000001-add_status.sql} (100%) diff --git a/migrations/20230807190031-add_status.sql b/migrations/20240320000001-add_status.sql similarity index 100% rename from migrations/20230807190031-add_status.sql rename to migrations/20240320000001-add_status.sql From 13f32a4291559136163f2517aa6b5051498afcfb Mon Sep 17 00:00:00 2001 From: keyansheng <65121402+keyansheng@users.noreply.github.com> Date: Wed, 27 Mar 2024 04:25:14 +0800 Subject: [PATCH 14/17] Fix migration name --- ...00001-add_status.sql => 20240320000001-add_status_message.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename migrations/{20240320000001-add_status.sql => 20240320000001-add_status_message.sql} (100%) diff --git a/migrations/20240320000001-add_status.sql b/migrations/20240320000001-add_status_message.sql similarity index 100% rename from migrations/20240320000001-add_status.sql rename to migrations/20240320000001-add_status_message.sql From 7689df9e74a112e27efd67c3e89e0791c1d434e9 Mon Sep 17 00:00:00 2001 From: keyansheng <65121402+keyansheng@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:55:55 +0800 Subject: [PATCH 15/17] Revert random added and deleted newlines and comments --- controller/stories/stories.go | 1 + model/stories.go | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/controller/stories/stories.go b/controller/stories/stories.go index 0e0965b..0d33768 100644 --- a/controller/stories/stories.go +++ b/controller/stories/stories.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" "github.com/go-chi/chi/v5" diff --git a/model/stories.go b/model/stories.go index f192d38..bbeee82 100644 --- a/model/stories.go +++ b/model/stories.go @@ -20,11 +20,11 @@ type Story struct { gorm.Model AuthorID uint Author User - GroupID *uint + GroupID *uint // null means this is a public story Group Group Title string Content string - PinOrder *int + PinOrder *int // nil if not pinned Status StoryStatus StatusMessage *string } @@ -154,7 +154,6 @@ func CreateStory(db *gorm.DB, story *Story) error { if err != nil { return database.HandleDBError(err, "story") } - return nil } @@ -184,6 +183,7 @@ func UpdateStory(db *gorm.DB, storyID int, newStory *Story) error { return database.HandleDBError(err, "story") } } + // Update remaining fields err = tx. Preload(clause.Associations). From a1f84d02de833b94a91b2a32fd5c41b40215a8c3 Mon Sep 17 00:00:00 2001 From: keyansheng <65121402+keyansheng@users.noreply.github.com> Date: Fri, 12 Apr 2024 10:43:43 +0800 Subject: [PATCH 16/17] Fix rejected route handler --- internal/router/router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/router/router.go b/internal/router/router.go index d86a904..5e9071d 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -58,7 +58,7 @@ func Setup(config *config.Config, injectMiddleWares []func(http.Handler) http.Ha r.Get("/draft", handleAPIError(stories.HandleListDraft)) r.Get("/pending", handleAPIError(stories.HandleListPending)) r.Get("/published", handleAPIError(stories.HandleListPublished)) - r.Get("/rejected", handleAPIError(stories.HandleListPublished)) + r.Get("/rejected", handleAPIError(stories.HandleListRejected)) r.Get("/{storyID}", handleAPIError(stories.HandleRead)) r.Put("/{storyID}", handleAPIError(stories.HandleUpdate)) r.Delete("/{storyID}", handleAPIError(stories.HandleDelete)) From 54d9a210b7a987cf15576afe15f398870d24dcdc Mon Sep 17 00:00:00 2001 From: keyansheng <65121402+keyansheng@users.noreply.github.com> Date: Fri, 12 Apr 2024 08:52:32 +0800 Subject: [PATCH 17/17] Run go mod tidy --- go.mod | 8 -------- go.sum | 20 -------------------- 2 files changed, 28 deletions(-) diff --git a/go.mod b/go.mod index 3f2174f..df43dc1 100644 --- a/go.mod +++ b/go.mod @@ -18,13 +18,11 @@ require ( ) require ( - github.com/BurntSushi/toml v1.2.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/google/go-cmp v0.5.9 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect @@ -44,11 +42,5 @@ require ( 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/tools v0.17.0 // indirect - golang.org/x/tools/gopls v0.14.2 // indirect - golang.org/x/vuln v1.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/tools v0.4.5 // indirect - mvdan.cc/gofumpt v0.4.0 // indirect - mvdan.cc/xurls/v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index a63ae4c..308f708 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/TwiN/go-color v1.4.0 h1:fNbOwOrvup5oj934UragnW0B1WKaAkkB85q19Y7h4ng= github.com/TwiN/go-color v1.4.0/go.mod h1:0QTVEPlu+AoCyTrho7bXbVkrCkVpdQr7YF7PYWEtSxM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -45,11 +43,8 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= @@ -76,27 +71,22 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6 github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rubenv/sql-migrate v1.5.1 h1:WsZo4jPQfjmddDTh/suANP2aKPA7/ekN0LzuuajgQEo= github.com/rubenv/sql-migrate v1.5.1/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -104,7 +94,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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/sync v0.0.0-20210220032951-036812b2e83c/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/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -114,15 +103,9 @@ 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/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools/gopls v0.14.2/go.mod h1:o2s+suLlFye+MHxEofsxJPkBQ/kT/ucP4iJV3ohjGEQ= -golang.org/x/vuln v1.0.1/go.mod h1:bb2hMwln/tqxg32BNY4CcxHWtHXuYa3SbIBmtsyjxtM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -130,6 +113,3 @@ gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo= gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0= gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -honnef.co/go/tools v0.4.5/go.mod h1:GUV+uIBCLpdf0/v6UhHHG/yzI/z6qPskBeQCjcNB96k= -mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= -mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg=