✨ Realms
This commit is contained in:
parent
28b4f11ccf
commit
0c8afb2bae
@ -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"`
|
||||
|
126
pkg/server/realms_api.go
Normal file
126
pkg/server/realms_api.go
Normal file
@ -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)
|
||||
}
|
@ -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{
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
40
pkg/services/realms.go
Normal file
40
pkg/services/realms.go
Normal file
@ -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
|
||||
}
|
@ -35,7 +35,7 @@ export default function PostItem(props: {
|
||||
return (
|
||||
<div class="post-item">
|
||||
<Show when={!props.noAuthor}>
|
||||
<a href={`/accounts/${props.post.author.id}`}>
|
||||
<a href={`/accounts/${props.post.author.name}`}>
|
||||
<div class="flex bg-base-200">
|
||||
<div class="avatar pl-[20px]">
|
||||
<div class="w-12">
|
||||
@ -47,7 +47,7 @@ export default function PostItem(props: {
|
||||
</div>
|
||||
<div class="flex items-center px-5">
|
||||
<div>
|
||||
<h3 class="font-bold text-sm">{props.post.author.name}</h3>
|
||||
<h3 class="font-bold text-sm">{props.post.author.nick}</h3>
|
||||
<p class="text-xs">{props.post.author.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -61,12 +61,12 @@ export default function PostItem(props: {
|
||||
|
||||
<div class="mt-2 flex gap-2">
|
||||
<For each={props.post.categories}>
|
||||
{item => <a href={`/categories/${item.alias}`} class="link link-primary">
|
||||
{item => <a class="link link-primary">
|
||||
#{item.name}
|
||||
</a>}
|
||||
</For>
|
||||
<For each={props.post.tags}>
|
||||
{item => <a href={`/tags/${item.alias}`} class="link link-primary">
|
||||
{item => <a class="link link-primary">
|
||||
#{item.name}
|
||||
</a>}
|
||||
</For>
|
||||
|
@ -184,7 +184,7 @@ export default function PostPublish(props: {
|
||||
<div role="alert" class="bg-base-200 flex justify-between">
|
||||
<div class="px-5 py-3">
|
||||
<i class="fa-solid fa-circle-info me-3"></i>
|
||||
You are reposting a post from <b>{props.reposting?.author?.name}</b>
|
||||
You are reposting a post from <b>{props.reposting?.author?.nick}</b>
|
||||
</div>
|
||||
<button type="reset" class="btn btn-ghost w-12" disabled={submitting()}>
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
@ -195,7 +195,7 @@ export default function PostPublish(props: {
|
||||
<div role="alert" class="bg-base-200 flex justify-between">
|
||||
<div class="px-5 py-3">
|
||||
<i class="fa-solid fa-circle-info me-3"></i>
|
||||
You are replying a post from <b>{props.replying?.author?.name}</b>
|
||||
You are replying a post from <b>{props.replying?.author?.nick}</b>
|
||||
</div>
|
||||
<button type="reset" class="btn btn-ghost w-12" disabled={submitting()}>
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
|
@ -11,7 +11,8 @@ interface MenuItem {
|
||||
|
||||
export default function Navbar() {
|
||||
const nav: MenuItem[] = [
|
||||
{ label: "Feed", href: "/" }
|
||||
{ label: "Feed", href: "/" },
|
||||
{ label: "Realms", href: "/realms" }
|
||||
];
|
||||
|
||||
const wellKnown = useWellKnown();
|
||||
|
Loading…
Reference in New Issue
Block a user