From 22ad4953088f38616327f2bca949de52073237c3 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 5 Feb 2024 19:25:56 +0800 Subject: [PATCH] :sparkles: Realm directory --- pkg/server/posts_api.go | 13 ++- pkg/server/realms_api.go | 26 +++++- pkg/server/startup.go | 4 +- pkg/services/posts.go | 24 ------ pkg/services/realms.go | 11 ++- pkg/view/src/components/NameCard.tsx | 2 +- pkg/view/src/components/PostPublish.tsx | 3 + pkg/view/src/index.tsx | 2 + pkg/view/src/layouts/shared/Navbar.tsx | 3 +- pkg/view/src/pages/account.tsx | 2 +- pkg/view/src/pages/realm.module.css | 3 + pkg/view/src/pages/realm.tsx | 106 ++++++++++++++++++++++++ pkg/view/src/pages/realms.tsx | 46 ++++++++++ 13 files changed, 212 insertions(+), 33 deletions(-) create mode 100644 pkg/view/src/pages/realm.module.css create mode 100644 pkg/view/src/pages/realm.tsx create mode 100644 pkg/view/src/pages/realms.tsx diff --git a/pkg/server/posts_api.go b/pkg/server/posts_api.go index 9bf9a9c..f3fac9b 100644 --- a/pkg/server/posts_api.go +++ b/pkg/server/posts_api.go @@ -18,7 +18,7 @@ func listPost(c *fiber.Ctx) error { authorId := c.QueryInt("authorId", 0) tx := database.C. - Where(&models.Post{RealmID: nil}). + Where("realm_id IS NULL"). Where("published_at <= ? OR published_at IS NULL", time.Now()). Order("created_at desc") @@ -55,6 +55,7 @@ func createPost(c *fiber.Ctx) error { Categories []models.Category `json:"categories"` Attachments []models.Attachment `json:"attachments"` PublishedAt *time.Time `json:"published_at"` + RealmID *uint `json:"realm_id"` RepostTo uint `json:"repost_to"` ReplyTo uint `json:"reply_to"` } @@ -90,8 +91,18 @@ func createPost(c *fiber.Ctx) error { } } + var realm *models.Realm + if data.RealmID != nil { + if err := database.C.Where(&models.Realm{ + BaseModel: models.BaseModel{ID: *data.RealmID}, + }).First(&realm).Error; err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + } + post, err := services.NewPost( user, + realm, data.Alias, data.Title, data.Content, diff --git a/pkg/server/realms_api.go b/pkg/server/realms_api.go index 50c333c..928702d 100644 --- a/pkg/server/realms_api.go +++ b/pkg/server/realms_api.go @@ -9,10 +9,32 @@ import ( "time" ) -func listRealms(c *fiber.Ctx) error { +func getRealm(c *fiber.Ctx) error { + id, _ := c.ParamsInt("realmId", 0) + + var realm models.Realm + if err := database.C.Where(&models.Realm{ + BaseModel: models.BaseModel{ID: uint(id)}, + }).First(&realm).Error; err != nil { + return fiber.NewError(fiber.StatusNotFound, err.Error()) + } + + return c.JSON(realm) +} + +func listRealm(c *fiber.Ctx) error { + realms, err := services.ListRealm() + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + return c.JSON(realms) +} + +func listOwnedRealm(c *fiber.Ctx) error { user := c.Locals("principal").(models.Account) - realms, err := services.ListRealms(user) + realms, err := services.ListRealmWithUser(user) if err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } diff --git a/pkg/server/startup.go b/pkg/server/startup.go index 2732330..3bcfc5e 100644 --- a/pkg/server/startup.go +++ b/pkg/server/startup.go @@ -74,7 +74,9 @@ func NewServer() { api.Put("/posts/:postId", auth, editPost) api.Delete("/posts/:postId", auth, deletePost) - api.Get("/realms", auth, listRealms) + api.Get("/realms", listRealm) + api.Get("/realms/me", auth, listOwnedRealm) + api.Get("/realms/:realmId", getRealm) api.Get("/realms/:realmId/posts", listPostInRealm) api.Post("/realms", auth, createRealm) api.Put("/realms/:realmId", auth, editRealm) diff --git a/pkg/services/posts.go b/pkg/services/posts.go index 3ec695d..065afd6 100644 --- a/pkg/services/posts.go +++ b/pkg/services/posts.go @@ -77,30 +77,6 @@ WHERE t.id IN (?)`, prefix, prefix, prefix), postIds).Scan(&reactInfo) } func NewPost( - user models.Account, - alias, title, content string, - attachments []models.Attachment, - categories []models.Category, - tags []models.Tag, - publishedAt *time.Time, - replyTo, repostTo *uint, -) (models.Post, error) { - return NewPostWithRealm( - user, - nil, - alias, - title, - content, - attachments, - categories, - tags, - publishedAt, - replyTo, - repostTo, - ) -} - -func NewPostWithRealm( user models.Account, realm *models.Realm, alias, title, content string, diff --git a/pkg/services/realms.go b/pkg/services/realms.go index fc5186d..9057f56 100644 --- a/pkg/services/realms.go +++ b/pkg/services/realms.go @@ -5,7 +5,16 @@ import ( "code.smartsheep.studio/hydrogen/interactive/pkg/models" ) -func ListRealms(user models.Account) ([]models.Realm, error) { +func ListRealm() ([]models.Realm, error) { + var realms []models.Realm + if err := database.C.Find(&realms).Error; err != nil { + return realms, err + } + + return realms, nil +} + +func ListRealmWithUser(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 diff --git a/pkg/view/src/components/NameCard.tsx b/pkg/view/src/components/NameCard.tsx index f291398..5a4476a 100644 --- a/pkg/view/src/components/NameCard.tsx +++ b/pkg/view/src/components/NameCard.tsx @@ -3,7 +3,7 @@ import { createSignal, Show } from "solid-js"; import styles from "./NameCard.module.css"; import { getAtk } from "../stores/userinfo.tsx"; -export default function NameCard(props: { accountId: number, onError: (messasge: string | null) => void }) { +export default function NameCard(props: { accountId: string, onError: (messasge: string | null) => void }) { const [info, setInfo] = createSignal(null); const [isFollowing, setIsFollowing] = createSignal(false); diff --git a/pkg/view/src/components/PostPublish.tsx b/pkg/view/src/components/PostPublish.tsx index ccf55cc..6c32154 100644 --- a/pkg/view/src/components/PostPublish.tsx +++ b/pkg/view/src/components/PostPublish.tsx @@ -8,6 +8,7 @@ export default function PostPublish(props: { replying?: any, reposting?: any, editing?: any, + realmId?: number, onReset: () => void, onError: (message: string | null) => void, onPost: () => void @@ -48,6 +49,7 @@ export default function PostPublish(props: { attachments: attachments(), categories: categories(), tags: tags(), + realm_id: props.realmId, published_at: data.published_at ? new Date(data.published_at as string) : new Date(), repost_to: props.reposting?.id, reply_to: props.replying?.id @@ -85,6 +87,7 @@ export default function PostPublish(props: { attachments: attachments(), categories: categories(), tags: tags(), + realm_id: props.realmId, published_at: data.published_at ? new Date(data.published_at as string) : new Date() }) }); diff --git a/pkg/view/src/index.tsx b/pkg/view/src/index.tsx index dae49ec..63e3cb6 100644 --- a/pkg/view/src/index.tsx +++ b/pkg/view/src/index.tsx @@ -22,6 +22,8 @@ render(() => ( import("./pages/feed.tsx"))}> import("./pages/global.tsx"))} /> + import("./pages/realms.tsx"))} /> + import("./pages/realm.tsx"))} /> import("./pages/account.tsx"))} /> import("./pages/auth/callout.tsx"))} /> diff --git a/pkg/view/src/layouts/shared/Navbar.tsx b/pkg/view/src/layouts/shared/Navbar.tsx index 6c0baae..7b238da 100644 --- a/pkg/view/src/layouts/shared/Navbar.tsx +++ b/pkg/view/src/layouts/shared/Navbar.tsx @@ -11,8 +11,7 @@ interface MenuItem { export default function Navbar() { const nav: MenuItem[] = [ - { label: "Feed", href: "/" }, - { label: "Realms", href: "/realms" } + { label: "Feed", href: "/" } ]; const wellKnown = useWellKnown(); diff --git a/pkg/view/src/pages/account.tsx b/pkg/view/src/pages/account.tsx index cbb9fd3..9caea93 100644 --- a/pkg/view/src/pages/account.tsx +++ b/pkg/view/src/pages/account.tsx @@ -64,7 +64,7 @@ export default function DashboardPage() { - + diff --git a/pkg/view/src/pages/realm.module.css b/pkg/view/src/pages/realm.module.css new file mode 100644 index 0000000..932298a --- /dev/null +++ b/pkg/view/src/pages/realm.module.css @@ -0,0 +1,3 @@ +.description { + color: var(--fallback-bc, oklch(var(--bc)/.8)); +} \ No newline at end of file diff --git a/pkg/view/src/pages/realm.tsx b/pkg/view/src/pages/realm.tsx new file mode 100644 index 0000000..4bf0e1d --- /dev/null +++ b/pkg/view/src/pages/realm.tsx @@ -0,0 +1,106 @@ +import { createSignal, Show } from "solid-js"; +import { createStore } from "solid-js/store"; +import { useParams } from "@solidjs/router"; + +import PostList from "../components/PostList.tsx"; +import PostPublish from "../components/PostPublish.tsx"; + +import styles from "./realm.module.css"; + +export default function RealmPage() { + const [error, setError] = createSignal(null); + + const [realm, setRealm] = createSignal(null); + const [page, setPage] = createSignal(0); + const [info, setInfo] = createSignal(null); + + const params = useParams(); + + async function readRealm() { + const res = await fetch(`/api/realms/${params["realmId"]}`); + if (res.status !== 200) { + setError(await res.text()); + } else { + setRealm(await res.json()); + } + } + + readRealm(); + + async function readPosts(pn?: number) { + if (pn) setPage(pn); + const res = await fetch(`/api/realms/${params["realmId"]}/posts?` + new URLSearchParams({ + take: (10).toString(), + offset: ((page() - 1) * 10).toString() + })); + if (res.status !== 200) { + setError(await res.text()); + } else { + setError(null); + setInfo(await res.json()); + } + } + + function setMeta(data: any, field: string, scroll = true) { + const meta: { [id: string]: any } = { + reposting: null, + replying: null, + editing: null + }; + meta[field] = data; + setPublishMeta(meta); + + if (scroll) window.scroll({ top: 0, behavior: "smooth" }); + } + + const [publishMeta, setPublishMeta] = createStore({ + replying: null, + reposting: null, + editing: null + }); + + return ( + <> +
+ + + +
+ +
+

{realm()?.name}

+

{realm()?.description}

+ +
+

Realm #{realm()?.id}

+
+
+ + setMeta(null, "none", false)} + onPost={() => readPosts()} + onError={setError} + /> + + setMeta(item, "reposting")} + onReply={(item) => setMeta(item, "replying")} + onEdit={(item) => setMeta(item, "editing")} + /> + + ); +} \ No newline at end of file diff --git a/pkg/view/src/pages/realms.tsx b/pkg/view/src/pages/realms.tsx new file mode 100644 index 0000000..a0cff56 --- /dev/null +++ b/pkg/view/src/pages/realms.tsx @@ -0,0 +1,46 @@ +import { createSignal, For, Show } from "solid-js"; + +export default function RealmDirectoryPage() { + const [error, setError] = createSignal(null); + + const [realms, setRealms] = createSignal(null); + + async function readRealms() { + const res = await fetch(`/api/realms`); + if (res.status !== 200) { + setError(await res.text()); + } else { + setRealms(await res.json()); + } + } + + readRealms(); + + return ( + <> +
+ + + +
+ + + {item =>
+

{item.name}

+

{item.description}

+ +
+ Jump in +
+
} +
+ + ); +} \ No newline at end of file