Realm directory

This commit is contained in:
LittleSheep 2024-02-05 19:25:56 +08:00
parent 0c8afb2bae
commit 22ad495308
13 changed files with 212 additions and 33 deletions

View File

@ -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,

View File

@ -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())
}

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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<any>(null);
const [isFollowing, setIsFollowing] = createSignal(false);

View File

@ -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()
})
});

View File

@ -22,6 +22,8 @@ render(() => (
<Router root={RootLayout}>
<Route path="/" component={lazy(() => import("./pages/feed.tsx"))}>
<Route path="/" component={lazy(() => import("./pages/global.tsx"))} />
<Route path="/realms" component={lazy(() => import("./pages/realms.tsx"))} />
<Route path="/realms/:realmId" component={lazy(() => import("./pages/realm.tsx"))} />
<Route path="/accounts/:accountId" component={lazy(() => import("./pages/account.tsx"))} />
</Route>
<Route path="/auth" component={lazy(() => import("./pages/auth/callout.tsx"))} />

View File

@ -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();

View File

@ -64,7 +64,7 @@ export default function DashboardPage() {
</Show>
</div>
<NameCard accountId={parseInt(params["accountId"])} onError={setError} />
<NameCard accountId={params["accountId"]} onError={setError} />
<dialog id="post-publish" class="modal">

View File

@ -0,0 +1,3 @@
.description {
color: var(--fallback-bc, oklch(var(--bc)/.8));
}

View File

@ -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<string | null>(null);
const [realm, setRealm] = createSignal<any>(null);
const [page, setPage] = createSignal(0);
const [info, setInfo] = createSignal<any>(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<any>({
replying: null,
reposting: null,
editing: null
});
return (
<>
<div id="alerts">
<Show when={error()}>
<div role="alert" class="alert alert-error">
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span class="capitalize">{error()}</span>
</div>
</Show>
</div>
<div class="px-7 pt-7 pb-5">
<h2 class="text-2xl font-bold">{realm()?.name}</h2>
<p>{realm()?.description}</p>
<div class={`${styles.description} text-sm mt-3`}>
<p>Realm #{realm()?.id}</p>
</div>
</div>
<PostPublish
realmId={parseInt(params["realmId"])}
replying={publishMeta.replying}
reposting={publishMeta.reposting}
editing={publishMeta.editing}
onReset={() => setMeta(null, "none", false)}
onPost={() => readPosts()}
onError={setError}
/>
<PostList
info={info()}
onUpdate={readPosts}
onError={setError}
onRepost={(item) => setMeta(item, "reposting")}
onReply={(item) => setMeta(item, "replying")}
onEdit={(item) => setMeta(item, "editing")}
/>
</>
);
}

View File

@ -0,0 +1,46 @@
import { createSignal, For, Show } from "solid-js";
export default function RealmDirectoryPage() {
const [error, setError] = createSignal<string | null>(null);
const [realms, setRealms] = createSignal<any>(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 (
<>
<div id="alerts">
<Show when={error()}>
<div role="alert" class="alert alert-error">
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span class="capitalize">{error()}</span>
</div>
</Show>
</div>
<For each={realms()}>
{item => <div class="px-7 pt-7 pb-5 border-t border-base-200">
<h2 class="text-xl font-bold">{item.name}</h2>
<p>{item.description}</p>
<div class="mt-2">
<a href={`/realms/${item.id}`} class="link">Jump in</a>
</div>
</div>}
</For>
</>
);
}