From 0c8afb2baef3a0757a928b4d22b3085e5c466330 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 5 Feb 2024 15:51:31 +0800 Subject: [PATCH] :sparkles: Realms --- pkg/models/accounts.go | 1 + pkg/server/realms_api.go | 126 ++++++++++++++++++++++++ pkg/server/startup.go | 6 ++ pkg/server/users_api.go | 4 +- pkg/services/auth.go | 13 ++- pkg/services/posts.go | 16 +-- pkg/services/realms.go | 40 ++++++++ pkg/view/src/components/PostItem.tsx | 8 +- pkg/view/src/components/PostPublish.tsx | 4 +- pkg/view/src/layouts/shared/Navbar.tsx | 3 +- 10 files changed, 204 insertions(+), 17 deletions(-) create mode 100644 pkg/server/realms_api.go create mode 100644 pkg/services/realms.go diff --git a/pkg/models/accounts.go b/pkg/models/accounts.go index e736c33..fe22f8d 100644 --- a/pkg/models/accounts.go +++ b/pkg/models/accounts.go @@ -9,6 +9,7 @@ type Account struct { BaseModel Name string `json:"name"` + Nick string `json:"nick"` Avatar string `json:"avatar"` Description string `json:"description"` EmailAddress string `json:"email_address"` diff --git a/pkg/server/realms_api.go b/pkg/server/realms_api.go new file mode 100644 index 0000000..50c333c --- /dev/null +++ b/pkg/server/realms_api.go @@ -0,0 +1,126 @@ +package server + +import ( + "code.smartsheep.studio/hydrogen/interactive/pkg/database" + "code.smartsheep.studio/hydrogen/interactive/pkg/models" + "code.smartsheep.studio/hydrogen/interactive/pkg/services" + "github.com/gofiber/fiber/v2" + "github.com/samber/lo" + "time" +) + +func listRealms(c *fiber.Ctx) error { + user := c.Locals("principal").(models.Account) + + realms, err := services.ListRealms(user) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + return c.JSON(realms) +} + +func listPostInRealm(c *fiber.Ctx) error { + take := c.QueryInt("take", 0) + offset := c.QueryInt("offset", 0) + authorId := c.QueryInt("authorId", 0) + + realmId, _ := c.ParamsInt("realmId", 0) + + tx := database.C. + Where(&models.Post{RealmID: lo.ToPtr(uint(realmId))}). + Where("published_at <= ? OR published_at IS NULL", time.Now()). + Order("created_at desc") + + if authorId > 0 { + tx = tx.Where(&models.Post{AuthorID: uint(authorId)}) + } + + var count int64 + if err := tx. + Model(&models.Post{}). + Count(&count).Error; err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + + posts, err := services.ListPost(tx, take, offset) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + return c.JSON(fiber.Map{ + "count": count, + "data": posts, + }) +} + +func createRealm(c *fiber.Ctx) error { + user := c.Locals("principal").(models.Account) + if user.PowerLevel < 10 { + return fiber.NewError(fiber.StatusForbidden, "require power level 10 to create realm") + } + + var data struct { + Name string `json:"name" validate:"required"` + Description string `json:"description"` + } + + if err := BindAndValidate(c, &data); err != nil { + return err + } + + realm, err := services.NewRealm(user, data.Name, data.Description) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + return c.JSON(realm) +} + +func editRealm(c *fiber.Ctx) error { + user := c.Locals("principal").(models.Account) + id, _ := c.ParamsInt("realmId", 0) + + var data struct { + Name string `json:"name" validate:"required"` + Description string `json:"description"` + } + + if err := BindAndValidate(c, &data); err != nil { + return err + } + + var realm models.Realm + if err := database.C.Where(&models.Realm{ + BaseModel: models.BaseModel{ID: uint(id)}, + AccountID: user.ID, + }).First(&realm).Error; err != nil { + return fiber.NewError(fiber.StatusNotFound, err.Error()) + } + + realm, err := services.EditRealm(realm, data.Name, data.Description) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + return c.JSON(realm) +} + +func deleteRealm(c *fiber.Ctx) error { + user := c.Locals("principal").(models.Account) + id, _ := c.ParamsInt("realmId", 0) + + var realm models.Realm + if err := database.C.Where(&models.Realm{ + BaseModel: models.BaseModel{ID: uint(id)}, + AccountID: user.ID, + }).First(&realm).Error; err != nil { + return fiber.NewError(fiber.StatusNotFound, err.Error()) + } + + if err := services.DeleteRealm(realm); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + return c.SendStatus(fiber.StatusOK) +} diff --git a/pkg/server/startup.go b/pkg/server/startup.go index 47dddd6..2732330 100644 --- a/pkg/server/startup.go +++ b/pkg/server/startup.go @@ -73,6 +73,12 @@ func NewServer() { api.Post("/posts/:postId/react/:reactType", auth, reactPost) api.Put("/posts/:postId", auth, editPost) api.Delete("/posts/:postId", auth, deletePost) + + api.Get("/realms", auth, listRealms) + api.Get("/realms/:realmId/posts", listPostInRealm) + api.Post("/realms", auth, createRealm) + api.Put("/realms/:realmId", auth, editRealm) + api.Delete("/realms/:realmId", auth, deleteRealm) } A.Use("/", cache.New(cache.Config{ diff --git a/pkg/server/users_api.go b/pkg/server/users_api.go index 4158539..ca24a2e 100644 --- a/pkg/server/users_api.go +++ b/pkg/server/users_api.go @@ -21,11 +21,11 @@ func getUserinfo(c *fiber.Ctx) error { } func getOthersInfo(c *fiber.Ctx) error { - accountId, _ := c.ParamsInt("accountId", 0) + accountId := c.Params("accountId") var data models.Account if err := database.C. - Where(&models.Account{BaseModel: models.BaseModel{ID: uint(accountId)}}). + Where(&models.Account{Name: accountId}). First(&data).Error; err != nil { return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } diff --git a/pkg/services/auth.go b/pkg/services/auth.go index c843dc4..9fcd326 100644 --- a/pkg/services/auth.go +++ b/pkg/services/auth.go @@ -14,6 +14,7 @@ import ( type PassportUserinfo struct { Sub string `json:"sub"` + Name string `json:"name"` Email string `json:"email"` Picture string `json:"picture"` PreferredUsername string `json:"preferred_username"` @@ -28,7 +29,8 @@ func LinkAccount(userinfo PassportUserinfo) (models.Account, error) { }).First(&account).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { account = models.Account{ - Name: userinfo.PreferredUsername, + Name: userinfo.Name, + Nick: userinfo.PreferredUsername, Avatar: userinfo.Picture, EmailAddress: userinfo.Email, PowerLevel: 0, @@ -39,7 +41,14 @@ func LinkAccount(userinfo PassportUserinfo) (models.Account, error) { return account, err } - return account, nil + account.Name = userinfo.Name + account.Nick = userinfo.PreferredUsername + account.Avatar = userinfo.Picture + account.EmailAddress = userinfo.Email + + err := database.C.Save(&account).Error + + return account, err } func GetToken(account models.Account) (string, string, error) { diff --git a/pkg/services/posts.go b/pkg/services/posts.go index 1fb9f81..3ec695d 100644 --- a/pkg/services/posts.go +++ b/pkg/services/posts.go @@ -12,11 +12,8 @@ import ( "gorm.io/gorm" ) -func ListPost(tx *gorm.DB, take int, offset int) ([]*models.Post, error) { - var posts []*models.Post - if err := tx. - Limit(take). - Offset(offset). +func PreloadRelatedPost(tx *gorm.DB) *gorm.DB { + return tx. Preload("Author"). Preload("Attachments"). Preload("Categories"). @@ -30,7 +27,14 @@ func ListPost(tx *gorm.DB, take int, offset int) ([]*models.Post, error) { Preload("RepostTo.Categories"). Preload("ReplyTo.Categories"). Preload("RepostTo.Tags"). - Preload("ReplyTo.Tags"). + Preload("ReplyTo.Tags") +} + +func ListPost(tx *gorm.DB, take int, offset int) ([]*models.Post, error) { + var posts []*models.Post + if err := PreloadRelatedPost(tx). + Limit(take). + Offset(offset). Find(&posts).Error; err != nil { return posts, err } diff --git a/pkg/services/realms.go b/pkg/services/realms.go new file mode 100644 index 0000000..fc5186d --- /dev/null +++ b/pkg/services/realms.go @@ -0,0 +1,40 @@ +package services + +import ( + "code.smartsheep.studio/hydrogen/interactive/pkg/database" + "code.smartsheep.studio/hydrogen/interactive/pkg/models" +) + +func ListRealms(user models.Account) ([]models.Realm, error) { + var realms []models.Realm + if err := database.C.Where(&models.Realm{AccountID: user.ID}).Find(&realms).Error; err != nil { + return realms, err + } + + return realms, nil +} + +func NewRealm(user models.Account, name, description string) (models.Realm, error) { + realm := models.Realm{ + Name: name, + Description: description, + AccountID: user.ID, + } + + err := database.C.Save(&realm).Error + + return realm, err +} + +func EditRealm(realm models.Realm, name, description string) (models.Realm, error) { + realm.Name = name + realm.Description = description + + err := database.C.Save(&realm).Error + + return realm, err +} + +func DeleteRealm(realm models.Realm) error { + return database.C.Delete(&realm).Error +} diff --git a/pkg/view/src/components/PostItem.tsx b/pkg/view/src/components/PostItem.tsx index 3c8decd..042b84d 100644 --- a/pkg/view/src/components/PostItem.tsx +++ b/pkg/view/src/components/PostItem.tsx @@ -35,7 +35,7 @@ export default function PostItem(props: { return (
- +
@@ -47,7 +47,7 @@ export default function PostItem(props: {
-

{props.post.author.name}

+

{props.post.author.nick}

{props.post.author.description}

@@ -61,12 +61,12 @@ export default function PostItem(props: {
- {item => + {item => #{item.name} } - {item => + {item => #{item.name} } diff --git a/pkg/view/src/components/PostPublish.tsx b/pkg/view/src/components/PostPublish.tsx index 72f6652..ccf55cc 100644 --- a/pkg/view/src/components/PostPublish.tsx +++ b/pkg/view/src/components/PostPublish.tsx @@ -184,7 +184,7 @@ export default function PostPublish(props: {