From 19e7aea06da32095661cdbae729d0cdfc2302d3a Mon Sep 17 00:00:00 2001 From: Damillora Date: Sat, 16 Apr 2022 02:20:14 +0700 Subject: [PATCH] feat: revamp with tag editor --- pkg/app/post_routes.go | 18 ++++ pkg/app/tag_routes.go | 95 ++++++++++++++++++ pkg/app/tag_type_routes.go | 6 +- pkg/database/tag.go | 1 + pkg/models/create_update.go | 10 +- pkg/models/read.go | 8 ++ pkg/services/tag.go | 52 ++++++++++ pkg/services/user.go | 7 +- web/app/src/App.svelte | 25 +++-- web/app/src/Navbar.svelte | 3 + web/app/src/api.js | 61 ++++++++++++ .../src/components/Tag/EditTagPanel.svelte | 94 ++++++++++++++++++ .../src/components/Tag/ViewTagPanel.svelte | 38 ++++++++ .../TagNotes/EditTagNotesPanel.svelte | 47 +++++++++ .../TagNotes/ViewTagNotesPanel.svelte | 25 +++++ web/app/src/main.scss | 1 + web/app/src/routes/{ => Auth}/Login.svelte | 2 +- web/app/src/routes/{ => Auth}/Logout.svelte | 2 +- web/app/src/routes/{ => Auth}/Register.svelte | 2 +- web/app/src/routes/Edit.svelte | 97 ------------------- web/app/src/routes/{ => Post}/Post.svelte | 6 +- web/app/src/routes/{ => Post}/Posts.svelte | 8 +- web/app/src/routes/{ => Post}/Upload.svelte | 4 +- web/app/src/routes/Tags/Tag.svelte | 70 +++++++++++++ web/app/src/routes/{ => Tags}/Tags.svelte | 4 +- web/app/src/routes/User/Profile.svelte | 26 +++++ 26 files changed, 585 insertions(+), 127 deletions(-) create mode 100644 web/app/src/components/Tag/EditTagPanel.svelte create mode 100644 web/app/src/components/Tag/ViewTagPanel.svelte create mode 100644 web/app/src/components/TagNotes/EditTagNotesPanel.svelte create mode 100644 web/app/src/components/TagNotes/ViewTagNotesPanel.svelte rename web/app/src/routes/{ => Auth}/Login.svelte (97%) rename web/app/src/routes/{ => Auth}/Logout.svelte (79%) rename web/app/src/routes/{ => Auth}/Register.svelte (97%) delete mode 100644 web/app/src/routes/Edit.svelte rename web/app/src/routes/{ => Post}/Post.svelte (95%) rename web/app/src/routes/{ => Post}/Posts.svelte (96%) rename web/app/src/routes/{ => Post}/Upload.svelte (98%) create mode 100644 web/app/src/routes/Tags/Tag.svelte rename web/app/src/routes/{ => Tags}/Tags.svelte (86%) create mode 100644 web/app/src/routes/User/Profile.svelte diff --git a/pkg/app/post_routes.go b/pkg/app/post_routes.go index 1fc7377..9bc8053 100644 --- a/pkg/app/post_routes.go +++ b/pkg/app/post_routes.go @@ -152,6 +152,15 @@ func postCreate(c *gin.Context) { } func postUpdate(c *gin.Context) { + _, ok := c.Get("user") + if !ok { + c.JSON(http.StatusForbidden, models.ErrorResponse{ + Code: http.StatusBadRequest, + Message: "User don't exist", + }) + c.Abort() + } + id := c.Param("id") var model models.PostUpdateModel @@ -194,6 +203,15 @@ func postUpdate(c *gin.Context) { } func postDelete(c *gin.Context) { + _, ok := c.Get("user") + if !ok { + c.JSON(http.StatusForbidden, models.ErrorResponse{ + Code: http.StatusBadRequest, + Message: "User don't exist", + }) + c.Abort() + } + id := c.Param("id") err := services.DeletePost(id) diff --git a/pkg/app/tag_routes.go b/pkg/app/tag_routes.go index 0745ffa..73f3598 100644 --- a/pkg/app/tag_routes.go +++ b/pkg/app/tag_routes.go @@ -3,6 +3,8 @@ package app import ( "net/http" + "github.com/Damillora/Shioriko/pkg/middleware" + "github.com/Damillora/Shioriko/pkg/models" "github.com/Damillora/Shioriko/pkg/services" "github.com/gin-gonic/gin" ) @@ -11,8 +13,14 @@ func InitializeTagRoutes(g *gin.Engine) { unprotected := g.Group("/api/tag") { unprotected.GET("/", tagGet) + unprotected.GET("/:tag", tagGetOne) unprotected.GET("/autocomplete", tagAutocomplete) } + protected := g.Group("/api/tag").Use(middleware.AuthMiddleware()) + { + protected.PUT("/:tag/note", tagUpdateNote) + protected.PUT("/:tag", tagUpdate) + } } func tagGet(c *gin.Context) { @@ -20,7 +28,94 @@ func tagGet(c *gin.Context) { c.JSON(http.StatusOK, tags) } +func tagGetOne(c *gin.Context) { + tag := c.Param("tag") + tagObj, err := services.GetTag(tag) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse{ + Code: http.StatusBadRequest, + Message: err.Error(), + }) + } + + c.JSON(http.StatusOK, models.TagReadModel{ + TagID: tagObj.TagID, + TagName: tagObj.TagName, + TagType: tagObj.TagType, + TagNote: tagObj.TagNote, + PostCount: tagObj.PostCount, + }) +} + func tagAutocomplete(c *gin.Context) { tags := services.GetTagAutocomplete() c.JSON(http.StatusOK, tags) } + +func tagUpdateNote(c *gin.Context) { + _, ok := c.Get("user") + if !ok { + c.JSON(http.StatusForbidden, models.ErrorResponse{ + Code: http.StatusBadRequest, + Message: "User don't exist", + }) + c.Abort() + } + + var model models.TagNoteUpdateModel + err := c.ShouldBindJSON(&model) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse{ + Code: http.StatusBadRequest, + Message: err.Error(), + }) + c.Abort() + return + } + + tag := c.Param("tag") + err = services.UpdateTagNotes(tag, model.Note) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse{ + Code: http.StatusBadRequest, + Message: err.Error(), + }) + c.Abort() + } + + c.JSON(http.StatusOK, nil) +} + +func tagUpdate(c *gin.Context) { + _, ok := c.Get("user") + if !ok { + c.JSON(http.StatusForbidden, models.ErrorResponse{ + Code: http.StatusBadRequest, + Message: "User don't exist", + }) + c.Abort() + } + + var model models.TagUpdateModel + err := c.ShouldBindJSON(&model) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse{ + Code: http.StatusBadRequest, + Message: err.Error(), + }) + c.Abort() + return + } + + tag := c.Param("tag") + err = services.UpdateTag(tag, model) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse{ + Code: http.StatusBadRequest, + Message: err.Error(), + }) + c.Abort() + } + + c.JSON(http.StatusOK, nil) +} diff --git a/pkg/app/tag_type_routes.go b/pkg/app/tag_type_routes.go index 94c3c72..8dd6c80 100644 --- a/pkg/app/tag_type_routes.go +++ b/pkg/app/tag_type_routes.go @@ -12,10 +12,12 @@ import ( ) func InitializeTagTypeRoutes(g *gin.Engine) { - + unprotected := g.Group(("/api/tagtype")) + { + unprotected.GET("/", tagTypeGet) + } protected := g.Group("/api/tagtype").Use(middleware.AuthMiddleware()) { - protected.GET("/", tagTypeGet) protected.POST("/create", tagTypeCreate) protected.DELETE("/:id", tagTypeDelete) } diff --git a/pkg/database/tag.go b/pkg/database/tag.go index dd77d55..aa05fd5 100644 --- a/pkg/database/tag.go +++ b/pkg/database/tag.go @@ -11,5 +11,6 @@ type Tag struct { UpdatedAt time.Time TagTypeID uint TagType TagType + Note string `gorm:"type:text"` Posts []Post `gorm:"many2many:post_tags"` } diff --git a/pkg/models/create_update.go b/pkg/models/create_update.go index f289685..138568f 100644 --- a/pkg/models/create_update.go +++ b/pkg/models/create_update.go @@ -7,9 +7,10 @@ type UserCreateModel struct { } type UserUpdateModel struct { - Email string `json:"email" validate:"required,email"` - Username string `json:"username" validate:"required"` - Password string `json:"password"` + Email string `json:"email" validate:"required,email"` + Username string `json:"username" validate:"required"` + OldPassword string `json:"oldPassword"` + NewPassword string `json:"newPassword"` } type TagTypeCreateModel struct { @@ -26,6 +27,9 @@ type TagUpdateModel struct { TagTypeID uint `json:"tagTypeId" validate:"required"` } +type TagNoteUpdateModel struct { + Note string `json:"note" validate:"required"` +} type PostCreateModel struct { BlobID string `json:"blob_id" validate:"required"` SourceURL string `json:"source_url"` diff --git a/pkg/models/read.go b/pkg/models/read.go index e5d8c73..5817fe3 100644 --- a/pkg/models/read.go +++ b/pkg/models/read.go @@ -10,3 +10,11 @@ type PostReadModel struct { Height int `json:"height"` Uploader string `json:"uploader"` } + +type TagReadModel struct { + TagID string `json:"tagId"` + TagName string `json:"tagName"` + TagType string `json:"tagType"` + TagNote string `json:"tagNote"` + PostCount int `json:"postCount"` +} diff --git a/pkg/services/tag.go b/pkg/services/tag.go index cb19cb9..d81f6ec 100644 --- a/pkg/services/tag.go +++ b/pkg/services/tag.go @@ -42,6 +42,24 @@ func GetTagFilter(tagObjs []database.Tag) []models.TagListItem { Find(&tags, tagIds) return tags } + +func GetTag(tagString string) (*models.TagReadModel, error) { + tagObj, err := FindTag(tagString) + if err != nil { + return nil, err + } + var tagModel models.TagReadModel + + database.DB.Model(&tagObj). + Joins("join tag_types on tag_types.id = tags.tag_type_id"). + Joins("left join post_tags on post_tags.tag_id = tags.id"). + Select("tags.id as tag_id, tags.name as tag_name, tag_types.name as tag_type, tags.note as tag_note, count(post_tags.post_id) as post_count"). + Group("tags.id, tags.name, tag_types.name, tags.note"). + First(&tagModel, "tags.id = ? ", tagObj.ID) + + return &tagModel, nil +} + func GetTagAutocomplete() []string { var tags []string result := database.DB.Model(&database.Tag{}). @@ -134,6 +152,7 @@ func CreateOrUpdateTag(tagSyntax string) (*database.Tag, error) { return nil, errors.New("Malformed tag syntax") } } + func FindTag(tagSyntax string) (*database.Tag, error) { tagFields := strings.Split(tagSyntax, ":") var tagName string @@ -173,3 +192,36 @@ func ParseReadTags(tags []string) ([]database.Tag, error) { } return result, nil } + +func UpdateTagNotes(tagString string, notes string) error { + tagObj, err := FindTag(tagString) + if err != nil { + return err + } + + tagObj.Note = notes + + result := database.DB.Save(&tagObj) + if result.Error != nil { + return result.Error + } + + return nil +} + +func UpdateTag(tagString string, model models.TagUpdateModel) error { + tagObj, err := FindTag(tagString) + if err != nil { + return err + } + + tagObj.TagTypeID = model.TagTypeID + tagObj.Name = model.Name + + result := database.DB.Save(&tagObj) + if result.Error != nil { + return result.Error + } + + return nil +} diff --git a/pkg/services/user.go b/pkg/services/user.go index f09e3fe..34b6e29 100644 --- a/pkg/services/user.go +++ b/pkg/services/user.go @@ -50,7 +50,12 @@ func UpdateUser(id string, model models.UserUpdateModel) (*database.User, error) user.Username = model.Username if user.Password != "" { - passwd, err := bcrypt.GenerateFromPassword([]byte(model.Password), bcrypt.DefaultCost) + verifyErr := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(model.OldPassword)) + if verifyErr != nil { + return nil, verifyErr + } + + passwd, err := bcrypt.GenerateFromPassword([]byte(model.NewPassword), bcrypt.DefaultCost) if err != nil { return nil, err } diff --git a/web/app/src/App.svelte b/web/app/src/App.svelte index 91e133d..097079f 100644 --- a/web/app/src/App.svelte +++ b/web/app/src/App.svelte @@ -3,15 +3,21 @@ import Navbar from "./Navbar.svelte"; + import Home from "./routes/Home.svelte"; - import Posts from "./routes/Posts.svelte"; - import Post from "./routes/Post.svelte"; - import Login from "./routes/Login.svelte"; - import Logout from "./routes/Logout.svelte"; - import Upload from "./routes/Upload.svelte"; - import Edit from "./routes/Edit.svelte"; - import Tags from "./routes/Tags.svelte"; - import Register from "./routes/Register.svelte"; + + import Login from "./routes/Auth/Login.svelte"; + import Logout from "./routes/Auth/Logout.svelte"; + import Register from "./routes/Auth/Register.svelte"; + + import Posts from "./routes/Post/Posts.svelte"; + import Post from "./routes/Post/Post.svelte"; + import Upload from "./routes/Post/Upload.svelte"; + + import Tags from "./routes/Tags/Tags.svelte"; + import Tag from "./routes/Tags/Tag.svelte"; + + import Profile from "./routes/User/Profile.svelte"; export let url = ""; let baseURL = window.BASE_URL; @@ -23,12 +29,13 @@ - + + diff --git a/web/app/src/Navbar.svelte b/web/app/src/Navbar.svelte index 854e9fb..e9982c2 100644 --- a/web/app/src/Navbar.svelte +++ b/web/app/src/Navbar.svelte @@ -46,6 +46,9 @@ {#if loggedIn}