色々
This commit is contained in:
@@ -2,6 +2,7 @@ import generateUniqueId from "@/lib/id";
|
||||
import { Entity, EntityRepositoryType, Index, ManyToOne, OptionalProps, PrimaryKey, Property } from "@mikro-orm/core";
|
||||
import { UserEntity } from "@/modules/entities/User";
|
||||
import { ChannelRepository } from "@/modules/repositories/Channel";
|
||||
import { CommunityEntity } from "@/modules/entities/Community";
|
||||
|
||||
@Entity({
|
||||
tableName: "channel",
|
||||
@@ -32,6 +33,9 @@ export class ChannelEntity {
|
||||
})
|
||||
description!: string;
|
||||
|
||||
@ManyToOne(() => CommunityEntity)
|
||||
community!: CommunityEntity;
|
||||
|
||||
@ManyToOne(() => UserEntity)
|
||||
createdBy!: UserEntity;
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import generateUniqueId from "@/lib/id";
|
||||
import { Entity, EntityRepositoryType, Index, ManyToOne, OptionalProps, PrimaryKey, Property } from "@mikro-orm/core";
|
||||
import { UserEntity } from "@/modules/entities/User";
|
||||
import { CommunityRepository } from "@/modules/repositories/Community";
|
||||
|
||||
@Entity({
|
||||
tableName: "community",
|
||||
repository: () => CommunityRepository,
|
||||
})
|
||||
export class CommunityEntity {
|
||||
[OptionalProps]?: "id" | "createdAt";
|
||||
[EntityRepositoryType]?: CommunityRepository;
|
||||
|
||||
@PrimaryKey({
|
||||
type: "string",
|
||||
length: 10,
|
||||
onCreate: () => generateUniqueId(),
|
||||
})
|
||||
id!: string;
|
||||
|
||||
@Property({
|
||||
type: "string",
|
||||
length: 20,
|
||||
unique: true,
|
||||
})
|
||||
@Index()
|
||||
name!: string;
|
||||
|
||||
@Property({
|
||||
type: "string",
|
||||
length: 4096,
|
||||
})
|
||||
description!: string;
|
||||
|
||||
@Property({
|
||||
type: "string",
|
||||
nullable: true,
|
||||
})
|
||||
icon?: string;
|
||||
|
||||
@ManyToOne(() => UserEntity)
|
||||
createdBy!: UserEntity;
|
||||
|
||||
@Property({
|
||||
type: "datetime",
|
||||
onCreate: () => new Date(),
|
||||
})
|
||||
createdAt!: Date;
|
||||
}
|
||||
@@ -9,9 +9,10 @@ export class ChannelRepository extends EntityRepository<ChannelEntity> {
|
||||
name: z.string().trim().min(1).max(20),
|
||||
description: z.string().trim().min(1).max(4096),
|
||||
userid: UserRepository.schema.shape.userid,
|
||||
community: z.string().length(10),
|
||||
});
|
||||
|
||||
async findChannel(limit: number = 20, sinceData?: string) {
|
||||
async listChannel(community: string, limit: number = 20, sinceData?: string) {
|
||||
let since = sinceData ?? new Date();
|
||||
|
||||
if (
|
||||
@@ -32,6 +33,7 @@ export class ChannelRepository extends EntityRepository<ChannelEntity> {
|
||||
}
|
||||
|
||||
const findResult = await this.find({
|
||||
community,
|
||||
createdAt: {
|
||||
$lt: since,
|
||||
},
|
||||
@@ -57,7 +59,7 @@ export class ChannelRepository extends EntityRepository<ChannelEntity> {
|
||||
|
||||
async editChannel(
|
||||
target: ChannelEntity,
|
||||
data: Partial<Omit<z.infer<typeof ChannelRepository.schema>, "userid">>
|
||||
data: Partial<Omit<z.infer<typeof ChannelRepository.schema>, "userid" | "community">>
|
||||
) {
|
||||
await this.nativeUpdate(target, data);
|
||||
return target.id;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import { EntityRepository } from "@mikro-orm/postgresql";
|
||||
import { ErrorBase } from "@/errors";
|
||||
import z from "zod/v3";
|
||||
import { UserRepository } from "@/modules/repositories/User";
|
||||
import type { CommunityEntity } from "@/modules/entities/Community";
|
||||
|
||||
export class CommunityRepository extends EntityRepository<CommunityEntity> {
|
||||
public static schema = z.object({
|
||||
name: z.string().trim().min(1).max(20),
|
||||
description: z.string().trim().min(1).max(4096),
|
||||
userid: UserRepository.schema.shape.userid,
|
||||
icon: z.string().url(),
|
||||
});
|
||||
|
||||
async listCommunity(limit: number = 20, sinceData?: string) {
|
||||
let since = sinceData ?? new Date();
|
||||
|
||||
if (
|
||||
sinceData &&
|
||||
!isNaN(new Date(sinceData).getTime())
|
||||
) {
|
||||
const itCommunity = await this.findOne({ id: sinceData });
|
||||
|
||||
if (!itCommunity) {
|
||||
return ErrorBase({
|
||||
bad: "client",
|
||||
code: "community_not_found",
|
||||
message: "対象のコミュニティが見つかりませんでした。",
|
||||
});
|
||||
}
|
||||
|
||||
since = itCommunity.createdAt;
|
||||
}
|
||||
|
||||
const findResult = await this.find({
|
||||
createdAt: {
|
||||
$lt: since,
|
||||
},
|
||||
}, {
|
||||
orderBy: {
|
||||
createdAt: "DESC",
|
||||
},
|
||||
limit: limit,
|
||||
});
|
||||
|
||||
return findResult ?? [];
|
||||
}
|
||||
|
||||
async createCommunity(data: Omit<z.infer<typeof CommunityRepository.schema>, "icon">) {
|
||||
const community = this.create({
|
||||
...data,
|
||||
createdBy: data.userid,
|
||||
});
|
||||
|
||||
await this.em.persist(community).flush();
|
||||
return community.id;
|
||||
}
|
||||
|
||||
async editCommunity(
|
||||
target: CommunityEntity,
|
||||
data: Partial<Omit<z.infer<typeof CommunityRepository.schema>, "userid">>
|
||||
) {
|
||||
await this.nativeUpdate(target, data);
|
||||
return target.id;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ export default async function ChannelEdit(fastify: FastifyInstance) {
|
||||
return res.code(400).send(req.token);
|
||||
|
||||
const result = ChannelRepository.schema
|
||||
.omit({ userid: true }).partial()
|
||||
.omit({ userid: true, community: true }).partial()
|
||||
.merge(z.object({ id: z.string().length(10) }))
|
||||
.refine(data =>
|
||||
!Object.keys(data).length
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { DatabaseError, ErrorBase, InputError } from "@/errors";
|
||||
import Logger from "@/lib/logger";
|
||||
import { ChannelEntity } from "@/modules/entities/Channel";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import z from "zod/v3";
|
||||
|
||||
export default async function ChannelGet(fastify: FastifyInstance) {
|
||||
const logger = new Logger("Endpoint | channel/get");
|
||||
|
||||
fastify.post("/", async (req, res) => {
|
||||
res.header("Content-Type", "application/json");
|
||||
|
||||
if ("error" in req.token)
|
||||
return res.code(400).send(req.token);
|
||||
|
||||
const bodySchema = z.object({
|
||||
id: z.string().length(10),
|
||||
});
|
||||
|
||||
const result = bodySchema.safeParse(req.body);
|
||||
|
||||
if (!result.success) {
|
||||
return res.code(400).send(InputError(result.error.issues));
|
||||
}
|
||||
|
||||
try {
|
||||
const channelRepo = fastify.orm.em.getRepository(ChannelEntity);
|
||||
|
||||
const findResult = await channelRepo.find({
|
||||
id: result.data.id,
|
||||
});
|
||||
|
||||
if (findResult[0] === undefined) {
|
||||
return res.code(400).send(ErrorBase({
|
||||
bad: "client",
|
||||
code: "channel_not_found",
|
||||
message: "対象のチャンネルが見つかりませんでした。",
|
||||
}));
|
||||
}
|
||||
|
||||
return res.send({
|
||||
success: true,
|
||||
channel: findResult[0],
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error("Database Error:", err);
|
||||
|
||||
return res.code(500).send(DatabaseError());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -2,8 +2,9 @@ import type { FastifyInstance } from "fastify";
|
||||
import ChannelList from "./list";
|
||||
import ChannelCreate from "./create";
|
||||
import ChannelEdit from "./edit";
|
||||
import ChannelGet from "./get";
|
||||
|
||||
export default async function Setup(fastify: FastifyInstance) {
|
||||
export default async function Channel(fastify: FastifyInstance) {
|
||||
await fastify.register(ChannelList, {
|
||||
prefix: "/list",
|
||||
});
|
||||
@@ -15,4 +16,8 @@ export default async function Setup(fastify: FastifyInstance) {
|
||||
await fastify.register(ChannelEdit, {
|
||||
prefix: "/edit",
|
||||
});
|
||||
|
||||
await fastify.register(ChannelGet, {
|
||||
prefix: "/get",
|
||||
});
|
||||
}
|
||||
@@ -16,6 +16,7 @@ export default async function ChannelList(fastify: FastifyInstance) {
|
||||
const bodySchema = z.object({
|
||||
limit: z.number().optional(),
|
||||
since: z.string().optional(),
|
||||
community: z.string().length(10),
|
||||
});
|
||||
|
||||
const result = bodySchema.safeParse(req.body);
|
||||
@@ -27,10 +28,11 @@ export default async function ChannelList(fastify: FastifyInstance) {
|
||||
try {
|
||||
const channelRepo = fastify.orm.em.getRepository(ChannelEntity);
|
||||
|
||||
const findResult = await channelRepo.findChannel(
|
||||
const findResult = await channelRepo.listChannel(
|
||||
result.data.community,
|
||||
result.data.limit,
|
||||
result.data.since,
|
||||
) ?? [];
|
||||
);
|
||||
|
||||
if ("error" in findResult) {
|
||||
return res.code(400).send(findResult);
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { DatabaseError, InputError } from "@/errors";
|
||||
import Logger from "@/lib/logger";
|
||||
import { CommunityEntity } from "@/modules/entities/Community";
|
||||
import { CommunityRepository } from "@/modules/repositories/Community";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
|
||||
export default async function CommunityCreate(fastify: FastifyInstance) {
|
||||
const logger = new Logger("Endpoint | community/create");
|
||||
|
||||
fastify.post("/", async (req, res) => {
|
||||
res.header("Content-Type", "application/json");
|
||||
|
||||
if ("error" in req.token)
|
||||
return res.code(400).send(req.token);
|
||||
|
||||
const result = CommunityRepository.schema.omit({ icon: true }).safeParse({
|
||||
...req.body as any,
|
||||
userid: req.token.user.userid,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
return res.code(400).send(InputError(result.error.issues));
|
||||
}
|
||||
|
||||
try {
|
||||
const communityRepo = fastify.orm.em.getRepository(CommunityEntity);
|
||||
|
||||
const id = await communityRepo.createCommunity(result.data);
|
||||
|
||||
return res.send({
|
||||
success: true,
|
||||
id,
|
||||
});
|
||||
} catch (err: any) {
|
||||
if (err.name === "UniqueConstraintViolationException") {
|
||||
const duplicate = err.constraint.replace("community_", "").replace("_unique", "");
|
||||
|
||||
if (duplicate !== "id") {
|
||||
return res.code(400).send(InputError([
|
||||
{
|
||||
validation: "regex",
|
||||
code: "invalid_string",
|
||||
message: "Duplicate",
|
||||
path: [duplicate],
|
||||
},
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
logger.error("Database Error:", err);
|
||||
|
||||
return res.code(500).send(DatabaseError());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { DatabaseError, ErrorBase, InputError } from "@/errors";
|
||||
import Logger from "@/lib/logger";
|
||||
import { CommunityEntity } from "@/modules/entities/Community";
|
||||
import { CommunityRepository } from "@/modules/repositories/Community";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import z from "zod/v3";
|
||||
|
||||
export default async function CommunityEdit(fastify: FastifyInstance) {
|
||||
const logger = new Logger("Endpoint | community/edit");
|
||||
|
||||
fastify.post("/", async (req, res) => {
|
||||
res.header("Content-Type", "application/json");
|
||||
|
||||
if ("error" in req.token)
|
||||
return res.code(400).send(req.token);
|
||||
|
||||
const result = CommunityRepository.schema
|
||||
.omit({ userid: true }).partial()
|
||||
.merge(z.object({ id: z.string().length(10) }))
|
||||
.refine(data =>
|
||||
!Object.keys(data).length
|
||||
).safeParse(req.body);
|
||||
|
||||
if (!result.success) {
|
||||
return res.code(400).send(InputError(result.error.issues));
|
||||
}
|
||||
|
||||
try {
|
||||
const communityRepo = fastify.orm.em.getRepository(CommunityEntity);
|
||||
const itCommunity = await communityRepo.findOne({ id: result.data.id });
|
||||
|
||||
if (!itCommunity) {
|
||||
return res.code(400).send(ErrorBase({
|
||||
bad: "client",
|
||||
code: "community_not_found",
|
||||
message: "対象のコミュニティが見つかりませんでした。",
|
||||
}));
|
||||
}
|
||||
|
||||
const id = await communityRepo.editCommunity(itCommunity, result.data);
|
||||
|
||||
return res.send({
|
||||
success: true,
|
||||
id,
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error("Database Error:", err);
|
||||
|
||||
return res.code(500).send(DatabaseError());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { DatabaseError, ErrorBase, InputError } from "@/errors";
|
||||
import Logger from "@/lib/logger";
|
||||
import { CommunityEntity } from "@/modules/entities/Community";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import z from "zod/v3";
|
||||
|
||||
export default async function CommunityGet(fastify: FastifyInstance) {
|
||||
const logger = new Logger("Endpoint | community/get");
|
||||
|
||||
fastify.post("/", async (req, res) => {
|
||||
res.header("Content-Type", "application/json");
|
||||
|
||||
if ("error" in req.token)
|
||||
return res.code(400).send(req.token);
|
||||
|
||||
const bodySchema = z.object({
|
||||
id: z.string().length(10),
|
||||
});
|
||||
|
||||
const result = bodySchema.safeParse(req.body);
|
||||
|
||||
if (!result.success) {
|
||||
return res.code(400).send(InputError(result.error.issues));
|
||||
}
|
||||
|
||||
try {
|
||||
const communityRepo = fastify.orm.em.getRepository(CommunityEntity);
|
||||
|
||||
const findResult = await communityRepo.find({
|
||||
id: result.data.id,
|
||||
});
|
||||
|
||||
if (findResult[0] === undefined) {
|
||||
return res.code(400).send(ErrorBase({
|
||||
bad: "client",
|
||||
code: "community_not_found",
|
||||
message: "対象のコミュニティが見つかりませんでした。",
|
||||
}));
|
||||
}
|
||||
|
||||
return res.send({
|
||||
success: true,
|
||||
community: findResult[0],
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error("Database Error:", err);
|
||||
|
||||
return res.code(500).send(DatabaseError());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import CommunityList from "./list";
|
||||
import CommunityCreate from "./create";
|
||||
import CommunityEdit from "./edit";
|
||||
import CommunityGet from "./get";
|
||||
|
||||
export default async function Community(fastify: FastifyInstance) {
|
||||
await fastify.register(CommunityList, {
|
||||
prefix: "/list",
|
||||
});
|
||||
|
||||
await fastify.register(CommunityCreate, {
|
||||
prefix: "/create",
|
||||
});
|
||||
|
||||
await fastify.register(CommunityEdit, {
|
||||
prefix: "/edit",
|
||||
});
|
||||
|
||||
await fastify.register(CommunityGet, {
|
||||
prefix: "/get",
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { DatabaseError, InputError } from "@/errors";
|
||||
import Logger from "@/lib/logger";
|
||||
import { CommunityEntity } from "@/modules/entities/Community";
|
||||
import { UserEntity } from "@/modules/entities/User";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import z from "zod/v3";
|
||||
|
||||
export default async function CommunityList(fastify: FastifyInstance) {
|
||||
const logger = new Logger("Endpoint | community/list");
|
||||
|
||||
fastify.post("/", async (req, res) => {
|
||||
res.header("Content-Type", "application/json");
|
||||
|
||||
if ("error" in req.token)
|
||||
return res.code(400).send(req.token);
|
||||
|
||||
const bodySchema = z.object({
|
||||
limit: z.number().optional(),
|
||||
since: z.string().optional(),
|
||||
});
|
||||
|
||||
const result = bodySchema.safeParse(req.body);
|
||||
|
||||
if (!result.success) {
|
||||
return res.code(400).send(InputError(result.error.issues));
|
||||
}
|
||||
|
||||
try {
|
||||
const communityRepo = fastify.orm.em.getRepository(CommunityEntity);
|
||||
|
||||
const findResult = await communityRepo.listCommunity(
|
||||
result.data.limit,
|
||||
result.data.since,
|
||||
);
|
||||
|
||||
if ("error" in findResult) {
|
||||
return res.code(400).send(findResult);
|
||||
}
|
||||
|
||||
findResult.map((community) => ({
|
||||
...community,
|
||||
createdBy: community.createdBy.userid,
|
||||
}));
|
||||
|
||||
return res.send({
|
||||
success: true,
|
||||
communitys: findResult.map(community => ({
|
||||
...community,
|
||||
createdBy: community.createdBy.userid,
|
||||
})),
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error("Database Error:", err);
|
||||
|
||||
return res.code(500).send(DatabaseError());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -3,6 +3,8 @@ import Setup from "./setup";
|
||||
import Primary from "./primary";
|
||||
import Me from "./me";
|
||||
import ServerInfo from "./server-info";
|
||||
import Community from "./community";
|
||||
import Channel from "./channel";
|
||||
|
||||
export default async function Routes(fastify: FastifyInstance) {
|
||||
await fastify.register(Setup, {
|
||||
@@ -20,4 +22,12 @@ export default async function Routes(fastify: FastifyInstance) {
|
||||
await fastify.register(Me, {
|
||||
prefix: "/me",
|
||||
});
|
||||
|
||||
await fastify.register(Community, {
|
||||
prefix: "/community",
|
||||
});
|
||||
|
||||
await fastify.register(Channel, {
|
||||
prefix: "/channel",
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user