feat: category and channel endpoints
This commit is contained in:
39
concord-server/src/controller/categoryController.ts
Normal file
39
concord-server/src/controller/categoryController.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import{
|
||||
createCategory,
|
||||
getCategory,
|
||||
getCategoriesByInstance,
|
||||
updateCategory,
|
||||
deleteCategory,
|
||||
deleteAllCategoriesFromInstance,
|
||||
} from "../services/channelService";
|
||||
import{
|
||||
CreateCategoryInput,
|
||||
UpdateCategoryInput,
|
||||
DeleteCategoryInput,
|
||||
DeleteCategoriesByInstanceIdInput
|
||||
} from "../validators/categoryValidator";
|
||||
|
||||
export async function createNewCategory(data: CreateCategoryInput) {
|
||||
return await createCategory(data);
|
||||
}
|
||||
|
||||
export async function fetchCategoryData(id: string) {
|
||||
return await getCategory(id);
|
||||
}
|
||||
|
||||
export async function fetchCategoriesByInstance(instanceId: string) {
|
||||
return await getCategoriesByInstance(instanceId);
|
||||
}
|
||||
|
||||
export async function updateExistingCategory(data: UpdateCategoryInput) {
|
||||
return await updateCategory(data);
|
||||
}
|
||||
|
||||
export async function deleteExistingCategory(data: DeleteCategoryInput) {
|
||||
return await deleteCategory(data);
|
||||
}
|
||||
|
||||
export async function deleteAllCategoriesByInstance(data: DeleteCategoriesByInstanceIdInput) {
|
||||
return await deleteAllCategoriesFromInstance(data);
|
||||
}
|
||||
|
||||
38
concord-server/src/controller/channelController.ts
Normal file
38
concord-server/src/controller/channelController.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import{
|
||||
createChannel,
|
||||
getChannel,
|
||||
getChannelsByCategory,
|
||||
updateChannel,
|
||||
deleteChannel,
|
||||
deleteAllChannelsFromCategory
|
||||
} from "../services/channelService";
|
||||
import {
|
||||
CreateChannelInput,
|
||||
UpdateChannelInput,
|
||||
DeleteChannelInput,
|
||||
DeleteChannelsByCategoryIdInput
|
||||
} from "../validators/channelValidator";
|
||||
|
||||
export async function createNewChannel(data: CreateChannelInput) {
|
||||
return await createChannel(data);
|
||||
}
|
||||
|
||||
export async function fetchChannelData(id: string) {
|
||||
return await getChannel(id);
|
||||
}
|
||||
|
||||
export async function fetchChannelsByCategory(categoryId: string) {
|
||||
return await getChannelsByCategory(categoryId);
|
||||
}
|
||||
|
||||
export async function updateExistingChannel(data: UpdateChannelInput) {
|
||||
return await updateChannel(data);
|
||||
}
|
||||
|
||||
export async function deleteExistingChannel(data: DeleteChannelInput) {
|
||||
return await deleteChannel(data);
|
||||
}
|
||||
|
||||
export async function deleteAllChannelsByCategory(data: DeleteChannelsByCategoryIdInput) {
|
||||
return await deleteAllChannelsFromCategory(data);
|
||||
}
|
||||
254
concord-server/src/routes/categoryRoutes.ts
Normal file
254
concord-server/src/routes/categoryRoutes.ts
Normal file
@@ -0,0 +1,254 @@
|
||||
import {
|
||||
createNewCategory,
|
||||
fetchCategoryData,
|
||||
fetchCategoriesByInstance,
|
||||
updateExistingCategory,
|
||||
deleteExistingCategory,
|
||||
deleteAllCategoriesByInstance,
|
||||
} from "../controller/categoryController";
|
||||
|
||||
import {
|
||||
createCategorySchema,
|
||||
CreateCategoryInput,
|
||||
UpdateCategoryInput,
|
||||
DeleteCategoriesByInstanceIdInput,
|
||||
} from "../validators/categoryValidator";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { Hono } from "hono";
|
||||
import { describeRoute, resolver } from "hono-openapi";
|
||||
const categoryRoutes = new Hono()
|
||||
|
||||
categoryRoutes.post(
|
||||
"/category/create",
|
||||
describeRoute({
|
||||
description: "Create a new category",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success creating category",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema) },
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: "Bad Request - Invalid input data",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: "Unauthorized - Admin access required",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "User Id not found",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator("json", createCategorySchema),
|
||||
async (c) => {
|
||||
const data = c.req.valid("json") as CreateCategoryInput;
|
||||
const categoryData = await createNewCategory(data);
|
||||
if (categoryData) {
|
||||
return c.json(categoryData);
|
||||
} else {
|
||||
return c.json({ error: "Failed to create category" }, 400);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
categoryRoutes.get(
|
||||
"/:id",
|
||||
describeRoute({
|
||||
description: "Get category by id",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success getting category",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema) },
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "Category id not found",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema) },
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
const id = c.req.param("id");
|
||||
const categoryData = await fetchCategoryData(id);
|
||||
if (categoryData) {
|
||||
return c.json(categoryData);
|
||||
} else {
|
||||
return c.json({ error: "Category not found" }, 404);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
categoryRoutes.get(
|
||||
"",
|
||||
describeRoute({
|
||||
description: "Get all categories by instance id",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success getting all categories in instance",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema) },
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator("query", createCategorySchema),
|
||||
async (c) => {
|
||||
const instanceId = c.req.query("instanceId");
|
||||
if (!instanceId) {
|
||||
return c.json({ error: "No instance id provided" }, 400);
|
||||
}
|
||||
|
||||
const categoryData = await fetchCategoriesByInstance(instanceId);
|
||||
if (categoryData) {
|
||||
return c.json(categoryData);
|
||||
} else {
|
||||
return c.json({ error: "Error getting all categories from instance" }, 500);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
categoryRoutes.put(
|
||||
"/category/update",
|
||||
describeRoute({
|
||||
description: "Update an existing category",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success updating category",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema) },
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: "Bad Request - Invalid input data",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: "Unauthorized - Admin access required",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "Category id or User Id not found",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator("json", createCategorySchema),
|
||||
async (c) => {
|
||||
const data = c.req.valid("json") as UpdateCategoryInput;
|
||||
const categoryData = await updateExistingCategory(data);
|
||||
if (categoryData) {
|
||||
return c.json(categoryData);
|
||||
} else {
|
||||
return c.json({ error: "Failed to update category" }, 400);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
categoryRoutes.delete(
|
||||
"/category/delete",
|
||||
describeRoute({
|
||||
description: "Delete an existing category",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success deleting category",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema) },
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: "Bad Request - Invalid input data",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: "Unauthorized - Admin access required",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "Category id or User Id not found",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator("json", createCategorySchema),
|
||||
async (c) => {
|
||||
const data = c.req.valid("json") as UpdateCategoryInput;
|
||||
const categoryData = await deleteExistingCategory(data);
|
||||
if (categoryData) {
|
||||
return c.json(categoryData);
|
||||
} else {
|
||||
return c.json({ error: "Failed to delete category" }, 400);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
categoryRoutes.delete(
|
||||
"/categories/delete/:id",
|
||||
describeRoute({
|
||||
description: "Delete all categories by instance id",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success deleting all categories in instance",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema) },
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: "Bad Request - Invalid input data",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: "Unauthorized - Admin access required",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "Instance id or User Id not found",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createCategorySchema)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator("json", createCategorySchema),
|
||||
async (c) => {
|
||||
const data = c.req.valid("json") as DeleteCategoriesByInstanceIdInput;
|
||||
const categoryData = await deleteAllCategoriesByInstance(data);
|
||||
if (categoryData) {
|
||||
return c.json(categoryData);
|
||||
} else {
|
||||
return c.json({ error: "Failed to delete categories" }, 400);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
export { categoryRoutes };
|
||||
264
concord-server/src/routes/channelRoutes.ts
Normal file
264
concord-server/src/routes/channelRoutes.ts
Normal file
@@ -0,0 +1,264 @@
|
||||
import {
|
||||
createNewChannel,
|
||||
fetchChannelData,
|
||||
fetchChannelsByCategory,
|
||||
updateExistingChannel,
|
||||
deleteExistingChannel,
|
||||
deleteAllChannelsByCategory,
|
||||
} from "../controller/channelController";
|
||||
|
||||
import {
|
||||
createChannelSchema,
|
||||
getChannelSchema,
|
||||
getChannelsByCategoryIdSchema,
|
||||
updateChannelSchema,
|
||||
deleteChannelSchema,
|
||||
deleteChannelsByCategoryIdSchema,
|
||||
|
||||
CreateChannelInput,
|
||||
GetChannelInput,
|
||||
GetChannelsByCategoryIdInput,
|
||||
UpdateChannelInput,
|
||||
DeleteChannelInput,
|
||||
DeleteChannelsByCategoryIdInput,
|
||||
} from "../validators/channelValidator";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { Hono } from "hono";
|
||||
import { describeRoute, resolver } from "hono-openapi";
|
||||
|
||||
const channelRoutes = new Hono()
|
||||
|
||||
channelRoutes.post(
|
||||
"/channel/create",
|
||||
describeRoute({
|
||||
description: "Create a new channel",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success creating channel",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createChannelSchema) },
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: "Bad Request - Invalid input data",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createChannelSchema)},
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: "Unauthorized - Admin access required",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createChannelSchema)},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "User Id not found",
|
||||
content: {
|
||||
"application/json": { schema: resolver(createChannelSchema)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator("json", createChannelSchema),
|
||||
async (c) => {
|
||||
const data = c.req.valid("json") as CreateChannelInput;
|
||||
const channelData = await createNewChannel(data);
|
||||
if (channelData) {
|
||||
return c.json(channelData);
|
||||
} else {
|
||||
return c.json({ error: "Failed to create channel" }, 400);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
channelRoutes.get(
|
||||
"/:id",
|
||||
describeRoute({
|
||||
description: "Get channel by id",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success getting channel",
|
||||
content: {
|
||||
"application/json": { schema: resolver(getChannelSchema) },
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "Channel id not found",
|
||||
content: {
|
||||
"application/json": { schema: resolver(getChannelSchema) },
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
const id = c.req.param("id");
|
||||
const channelData = await fetchChannelData(id);
|
||||
if (channelData) {
|
||||
return c.json(channelData);
|
||||
} else {
|
||||
return c.json({ error: "Channel not found" }, 404);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
channelRoutes.get(
|
||||
"",
|
||||
describeRoute({
|
||||
description: "Get all channels by category id",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success getting all channels in category",
|
||||
content: {
|
||||
"application/json": { schema: resolver(getChannelsByCategoryIdSchema) },
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator("query", getChannelsByCategoryIdSchema),
|
||||
async (c) => {
|
||||
const categoryId = c.req.query("categoryId");
|
||||
if (!categoryId) {
|
||||
return c.json({ error: "No category id provided" }, 400);
|
||||
}
|
||||
|
||||
const channels = await fetchChannelsByCategory(categoryId);
|
||||
if (channels) {
|
||||
return c.json(channels);
|
||||
} else {
|
||||
return c.json({ error: "Error getting channels from category" }, 500);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
channelRoutes.put(
|
||||
"/channel/update",
|
||||
describeRoute({
|
||||
description: "Update an existing channel",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success updating channel",
|
||||
content: {
|
||||
"application/json": { schema: resolver(updateChannelSchema) },
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: "Bad Request - Invalid input data",
|
||||
content: {
|
||||
"application/json": { schema: resolver(updateChannelSchema)},
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: "Unauthorized - Admin access required",
|
||||
content: {
|
||||
"application/json": { schema: resolver(updateChannelSchema)},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "Channel id or User Id not found",
|
||||
content: {
|
||||
"application/json": { schema: resolver(updateChannelSchema)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator("json", updateChannelSchema),
|
||||
async (c) => {
|
||||
const data = c.req.valid("json") as UpdateChannelInput;
|
||||
const result = await updateExistingChannel(data);
|
||||
if (result) {
|
||||
return c.json(result);
|
||||
} else {
|
||||
return c.json({ error: "Failed to update channel" }, 400);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
channelRoutes.delete(
|
||||
"/channel/delete",
|
||||
describeRoute({
|
||||
description: "Delete an existing channel",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success deleting channel",
|
||||
content: {
|
||||
"application/json": { schema: resolver(deleteChannelSchema) },
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: "Bad Request - Invalid input data",
|
||||
content: {
|
||||
"application/json": { schema: resolver(deleteChannelSchema)},
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: "Unauthorized - Admin access required",
|
||||
content: {
|
||||
"application/json": { schema: resolver(deleteChannelSchema)},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "Channel id or User Id not found",
|
||||
content: {
|
||||
"application/json": { schema: resolver(deleteChannelSchema)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator("json", deleteChannelSchema),
|
||||
async (c) => {
|
||||
const data = c.req.valid("json") as DeleteChannelInput;
|
||||
const result = await deleteExistingChannel(data);
|
||||
if (result) {
|
||||
return c.json({ success: true });
|
||||
} else {
|
||||
return c.json({ error: "Failed to delete channel" }, 400);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
channelRoutes.delete(
|
||||
"/channels/delete-by-category",
|
||||
describeRoute({
|
||||
description: "Delete all channels by category id",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success deleting all channels in category",
|
||||
content: {
|
||||
"application/json": { schema: resolver(deleteChannelsByCategoryIdSchema) },
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: "Bad Request - Invalid input data",
|
||||
content: {
|
||||
"application/json": { schema: resolver(deleteChannelsByCategoryIdSchema)},
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description: "Unauthorized - Admin access required",
|
||||
content: {
|
||||
"application/json": { schema: resolver(deleteChannelsByCategoryIdSchema)},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "Category id or User Id not found",
|
||||
content: {
|
||||
"application/json": { schema: resolver(deleteChannelsByCategoryIdSchema)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator("json", deleteChannelsByCategoryIdSchema),
|
||||
async (c) => {
|
||||
const data = c.req.valid("json") as DeleteChannelsByCategoryIdInput;
|
||||
const result = await deleteAllChannelsByCategory(data);
|
||||
if (result) {
|
||||
return c.json({ success: true });
|
||||
} else {
|
||||
return c.json({ error: "Failed to delete channels" }, 400);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
export default channelRoutes ;
|
||||
@@ -2,10 +2,12 @@
|
||||
import { Hono } from "hono";
|
||||
import userRoutes from "./userRoutes";
|
||||
import messageRoutes from "./messageRoutes";
|
||||
import channelRoutes from "./channelRoutes";
|
||||
|
||||
const routes = new Hono();
|
||||
|
||||
routes.route("/user", userRoutes);
|
||||
routes.route("/message", messageRoutes);
|
||||
routes.route("/channel", channelRoutes);
|
||||
|
||||
export default routes;
|
||||
|
||||
450
concord-server/src/services/channelService.ts
Normal file
450
concord-server/src/services/channelService.ts
Normal file
@@ -0,0 +1,450 @@
|
||||
import{
|
||||
Channel,
|
||||
Category
|
||||
} from '@prisma/client';
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { getUserInformation, getUserCredentials } from './userService';
|
||||
import {
|
||||
CreateChannelInput,
|
||||
UpdateChannelInput,
|
||||
DeleteChannelInput,
|
||||
DeleteChannelsByCategoryIdInput
|
||||
} from '../validators/channelValidator';
|
||||
import{
|
||||
UpdateCategoryInput,
|
||||
DeleteCategoryInput,
|
||||
DeleteCategoriesByInstanceIdInput,
|
||||
CreateCategoryInput
|
||||
} from '../validators/categoryValidator';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
|
||||
export async function createCategory(data: CreateCategoryInput): Promise<Category | null>{
|
||||
try{
|
||||
|
||||
//Confirm if user exists and is admin
|
||||
const requestingUser = await getUserInformation(data.requestingUserId);
|
||||
const requestingUserCredentials = await getUserCredentials(
|
||||
data.requestingUserId,
|
||||
)
|
||||
|
||||
if (
|
||||
!requestingUser ||
|
||||
!requestingUserCredentials ||
|
||||
!requestingUser.admin ||
|
||||
requestingUserCredentials.token == null ||
|
||||
data.requestingUserToken != requestingUserCredentials.token
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const newCategory = await prisma.category.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
position: data.position
|
||||
}
|
||||
});
|
||||
|
||||
if(!newCategory){
|
||||
throw new Error("could not create category");
|
||||
}
|
||||
|
||||
let curInstance;
|
||||
if(data.instanceId){
|
||||
curInstance = await prisma.instance.findUnique({
|
||||
where: {
|
||||
id: data.instanceId
|
||||
},
|
||||
include: {
|
||||
Category: true
|
||||
}
|
||||
});
|
||||
|
||||
if(!curInstance){
|
||||
throw new Error("could not find instance to add category to");
|
||||
}
|
||||
|
||||
await prisma.category.update({
|
||||
where: {
|
||||
id: newCategory.id
|
||||
},
|
||||
data: {
|
||||
instanceId: curInstance.id
|
||||
}
|
||||
});
|
||||
|
||||
return newCategory;
|
||||
}
|
||||
|
||||
return newCategory;
|
||||
}catch(err){
|
||||
console.log("services::channelService::createCategory - ", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCategory(
|
||||
categoryId: string,
|
||||
): Promise<Category | null>{
|
||||
try{
|
||||
const category = await prisma.category.findUnique({
|
||||
where: {
|
||||
id: categoryId
|
||||
}
|
||||
});
|
||||
|
||||
if(!category){
|
||||
throw new Error("could not find category");
|
||||
}
|
||||
|
||||
return category;
|
||||
}catch(err){
|
||||
console.log("services::channelService::getCategory - ", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCategoriesByInstance(
|
||||
instanceId: string
|
||||
): Promise<Category[] | null>{
|
||||
try{
|
||||
const categories = await prisma.category.findMany({
|
||||
where: {
|
||||
instanceId: instanceId
|
||||
},
|
||||
include: {
|
||||
Channel: true
|
||||
},
|
||||
orderBy: {
|
||||
position: 'asc'
|
||||
}
|
||||
});
|
||||
|
||||
if(!categories){
|
||||
throw new Error("could not find categories for instance");
|
||||
}
|
||||
|
||||
return categories;
|
||||
}catch(err){
|
||||
console.log("services::channelService::getCategoriesByInstance - ", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateCategory(data: UpdateCategoryInput): Promise<Category | null>{
|
||||
try{
|
||||
|
||||
//Confirm if user exists and is admin
|
||||
const requestingUser = await getUserInformation(data.requestingUserId);
|
||||
const requestingUserCredentials = await getUserCredentials(
|
||||
data.requestingUserId,
|
||||
)
|
||||
|
||||
if (
|
||||
!requestingUser ||
|
||||
!requestingUserCredentials ||
|
||||
!requestingUser.admin ||
|
||||
requestingUserCredentials.token == null ||
|
||||
data.requestingUserToken != requestingUserCredentials.token
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedCategory = await prisma.category.update({
|
||||
where: {
|
||||
id: data.id
|
||||
},
|
||||
data: {
|
||||
name: data.name,
|
||||
position: data.position,
|
||||
Channel: data.channels ? { set: data.channels } : undefined
|
||||
}
|
||||
});
|
||||
|
||||
if(!updatedCategory){
|
||||
throw new Error("could not update category");
|
||||
}
|
||||
|
||||
return updatedCategory;
|
||||
}catch(err){
|
||||
console.log("services::channelService::updateCategory - ", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteCategory(data: DeleteCategoryInput): Promise<boolean | null>{
|
||||
try{
|
||||
|
||||
//Confirm if user exists and is admin
|
||||
const requestingUser = await getUserInformation(data.requestingUserId);
|
||||
const requestingUserCredentials = await getUserCredentials(
|
||||
data.requestingUserId,
|
||||
)
|
||||
|
||||
if (
|
||||
!requestingUser ||
|
||||
!requestingUserCredentials ||
|
||||
!requestingUser.admin ||
|
||||
requestingUserCredentials.token == null ||
|
||||
data.requestingUserToken != requestingUserCredentials.token
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const deleteAllChannels = await prisma.channel.deleteMany({
|
||||
where: {
|
||||
categoryId: data.id
|
||||
}
|
||||
});
|
||||
|
||||
if(deleteAllChannels.count === 0){
|
||||
throw new Error("could not delete channels from category");
|
||||
}
|
||||
|
||||
const deletedCategory = await prisma.category.delete({
|
||||
where: {
|
||||
id: data.id
|
||||
}
|
||||
});
|
||||
|
||||
if(!deletedCategory){
|
||||
throw new Error("could not delete category");
|
||||
}
|
||||
|
||||
return true;
|
||||
}catch(err){
|
||||
console.log("services::channelService::deleteCategory - ", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteAllCategoriesFromInstance(data: DeleteCategoriesByInstanceIdInput): Promise<boolean | null>{
|
||||
try{
|
||||
|
||||
//Confirm if user exists and is admin
|
||||
const requestingUser = await getUserInformation(data.requestingUserId);
|
||||
const requestingUserCredentials = await getUserCredentials(
|
||||
data.requestingUserId,
|
||||
)
|
||||
|
||||
if (
|
||||
!requestingUser ||
|
||||
!requestingUserCredentials ||
|
||||
!requestingUser.admin ||
|
||||
requestingUserCredentials.token == null ||
|
||||
data.requestingUserToken != requestingUserCredentials.token
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const deletedCategories = await prisma.category.deleteMany({
|
||||
where: {
|
||||
instanceId: data.instanceId
|
||||
}
|
||||
});
|
||||
|
||||
if(deletedCategories.count === 0){
|
||||
throw new Error("could not delete categories from instance");
|
||||
}
|
||||
|
||||
return true;
|
||||
}catch(err){
|
||||
console.log("services::channelService::deleteAllCategoriesFromInstance - ", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function createChannel(data: CreateChannelInput): Promise<Channel | null>{
|
||||
try{
|
||||
|
||||
//Confirm if user exists and is admin
|
||||
const requestingUser = await getUserInformation(data.requestingUserId);
|
||||
const requestingUserCredentials = await getUserCredentials(
|
||||
data.requestingUserId,
|
||||
)
|
||||
|
||||
if (
|
||||
!requestingUser ||
|
||||
!requestingUserCredentials ||
|
||||
!requestingUser.admin ||
|
||||
requestingUserCredentials.token == null ||
|
||||
data.requestingUserToken != requestingUserCredentials.token
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const newChannel = await prisma.channel.create({
|
||||
data: {
|
||||
type: data.type,
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
categoryId: data.categoryId ? data.categoryId : null
|
||||
}
|
||||
});
|
||||
|
||||
if(!newChannel){
|
||||
throw new Error("could not create channel");
|
||||
}
|
||||
|
||||
return newChannel;
|
||||
}catch(err){
|
||||
console.log("services::channelService::createChannel - ", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getChannel(
|
||||
channelId: string
|
||||
): Promise<Channel | null>{
|
||||
try{
|
||||
const channel = await prisma.channel.findUnique({
|
||||
where: {
|
||||
id: channelId
|
||||
}
|
||||
});
|
||||
|
||||
if(!channel){
|
||||
throw new Error("could not find channel");
|
||||
}
|
||||
|
||||
return channel;
|
||||
}catch(err){
|
||||
console.log("services::channelService::getChannel - ", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getChannelsByCategory(
|
||||
categoryId: string
|
||||
): Promise<Channel[] | null>{
|
||||
try{
|
||||
const channels = await prisma.channel.findMany({
|
||||
where: {
|
||||
categoryId: categoryId
|
||||
}
|
||||
});
|
||||
|
||||
if(!channels){
|
||||
throw new Error("could not find channels for category");
|
||||
}
|
||||
return channels;
|
||||
}
|
||||
catch(err){
|
||||
console.log("services::channelService::getChannelsByCategory - ", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateChannel(data: UpdateChannelInput): Promise<Channel | null>{
|
||||
try{
|
||||
|
||||
//Confirm if user exists and is admin
|
||||
const requestingUser = await getUserInformation(data.requestingUserId);
|
||||
const requestingUserCredentials = await getUserCredentials(
|
||||
data.requestingUserId,
|
||||
)
|
||||
|
||||
if (
|
||||
!requestingUser ||
|
||||
!requestingUserCredentials ||
|
||||
!requestingUser.admin ||
|
||||
requestingUserCredentials.token == null ||
|
||||
data.requestingUserToken != requestingUserCredentials.token
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedChannel = await prisma.channel.update({
|
||||
where: {
|
||||
id: data.id
|
||||
},
|
||||
data: {
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
categoryId: data.categoryId ? data.categoryId : undefined
|
||||
}
|
||||
});
|
||||
|
||||
if(!updatedChannel){
|
||||
throw new Error("could not update channel");
|
||||
}
|
||||
|
||||
return updatedChannel;
|
||||
}catch(err){
|
||||
console.log("services::channelService::updateChannel - ", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteChannel(data: DeleteChannelInput): Promise<boolean | null>{
|
||||
try{
|
||||
|
||||
//Confirm if user exists and is admin
|
||||
const requestingUser = await getUserInformation(data.requestingUserId);
|
||||
const requestingUserCredentials = await getUserCredentials(
|
||||
data.requestingUserId,
|
||||
)
|
||||
|
||||
if (
|
||||
!requestingUser ||
|
||||
!requestingUserCredentials ||
|
||||
!requestingUser.admin ||
|
||||
requestingUserCredentials.token == null ||
|
||||
data.requestingUserToken != requestingUserCredentials.token
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const deletedChannel = await prisma.channel.delete({
|
||||
where: {
|
||||
id: data.id
|
||||
}
|
||||
});
|
||||
|
||||
if(!deletedChannel){
|
||||
throw new Error("could not delete channel");
|
||||
}
|
||||
|
||||
return true;
|
||||
}catch(err){
|
||||
console.log("services::channelService::deleteChannel - ", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteAllChannelsFromCategory(data: DeleteChannelsByCategoryIdInput): Promise<boolean | null>
|
||||
{
|
||||
try{
|
||||
//Confirm if user exists and is admin
|
||||
const requestingUser = await getUserInformation(data.requestingUserId);
|
||||
const requestingUserCredentials = await getUserCredentials(
|
||||
data.requestingUserId,
|
||||
)
|
||||
|
||||
if (
|
||||
!requestingUser ||
|
||||
!requestingUserCredentials ||
|
||||
!requestingUser.admin ||
|
||||
requestingUserCredentials.token == null ||
|
||||
data.requestingUserToken != requestingUserCredentials.token
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const deletedChannels = await prisma.channel.deleteMany({
|
||||
where: {
|
||||
categoryId: data.categoryId
|
||||
}
|
||||
});
|
||||
|
||||
if(deletedChannels.count === 0){
|
||||
throw new Error("could not delete channels from category");
|
||||
}
|
||||
|
||||
return true;
|
||||
}catch(err){
|
||||
console.log("services::channelService::deleteAllChannelsFromCategory - ", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import {
|
||||
Message,
|
||||
MessagePing,
|
||||
|
||||
55
concord-server/src/validators/categoryValidator.ts
Normal file
55
concord-server/src/validators/categoryValidator.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
//category validators
|
||||
|
||||
export const createCategorySchema = z.object({
|
||||
name: z.string().min(1).max(50),
|
||||
position: z.number().min(0),
|
||||
instanceId : z.uuidv7().optional(),
|
||||
admin: z.boolean(),
|
||||
requestingUserId: z.uuidv7(),
|
||||
requestingUserToken: z.uuidv4()
|
||||
})
|
||||
|
||||
export const getCategorySchema = z.object({
|
||||
id: z.uuidv7()
|
||||
})
|
||||
|
||||
export const getCategoriesByInstanceIdSchema = z.object({
|
||||
instanceId: z.uuidv7()
|
||||
|
||||
})
|
||||
|
||||
export const updateCategorySchema = z.object({
|
||||
id: z.uuidv7(),
|
||||
name: z.string().min(1).max(50).optional(),
|
||||
position: z.number().min(0).optional(),
|
||||
channels: z.array(z.object({
|
||||
id: z.string()
|
||||
})).optional(),
|
||||
admin: z.boolean(),
|
||||
requestingUserId: z.uuidv7(),
|
||||
requestingUserToken: z.uuidv4()
|
||||
})
|
||||
|
||||
export const deleteCategorySchema = z.object({
|
||||
id: z.uuidv7(),
|
||||
admin: z.boolean(),
|
||||
requestingUserId: z.uuidv7(),
|
||||
requestingUserToken: z.uuidv4()
|
||||
})
|
||||
|
||||
export const deleteCategoriesByInstanceIdSchema = z.object({
|
||||
instanceId: z.uuidv7(),
|
||||
admin: z.boolean(),
|
||||
requestingUserId: z.uuidv7(),
|
||||
requestingUserToken: z.uuidv4()
|
||||
})
|
||||
|
||||
|
||||
export type CreateCategoryInput = z.infer<typeof createCategorySchema>
|
||||
export type GetCategoryInput = z.infer<typeof getCategorySchema>
|
||||
export type GetCategoriesByInstanceIdInput = z.infer<typeof getCategoriesByInstanceIdSchema>
|
||||
export type UpdateCategoryInput = z.infer<typeof updateCategorySchema>
|
||||
export type DeleteCategoryInput = z.infer<typeof deleteCategorySchema>
|
||||
export type DeleteCategoriesByInstanceIdInput = z.infer<typeof deleteCategoriesByInstanceIdSchema>
|
||||
52
concord-server/src/validators/channelValidator.ts
Normal file
52
concord-server/src/validators/channelValidator.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { z } from "zod";
|
||||
|
||||
//channel validators
|
||||
|
||||
export const createChannelSchema = z.object({
|
||||
type: z.enum(['text', 'voice']),
|
||||
name: z.string().min(1).max(50),
|
||||
description: z.string().max(255),
|
||||
categoryId: z.uuidv7().optional(),
|
||||
admin: z.boolean(),
|
||||
requestingUserId: z.uuidv7(),
|
||||
requestingUserToken: z.uuidv4()
|
||||
})
|
||||
|
||||
export const getChannelSchema = z.object({
|
||||
id: z.uuidv7()
|
||||
})
|
||||
|
||||
export const getChannelsByCategoryIdSchema = z.object({
|
||||
categoryId: z.uuidv7()
|
||||
})
|
||||
|
||||
export const updateChannelSchema = z.object({
|
||||
id: z.uuidv7(),
|
||||
name: z.string().min(1).max(50).optional(),
|
||||
description: z.string().max(255).optional(),
|
||||
categoryId: z.uuidv7().optional(),
|
||||
admin: z.boolean(),
|
||||
requestingUserId: z.uuidv7(),
|
||||
requestingUserToken: z.uuidv4()
|
||||
})
|
||||
|
||||
export const deleteChannelSchema = z.object({
|
||||
id: z.uuidv7(),
|
||||
admin: z.boolean(),
|
||||
requestingUserId: z.uuidv7(),
|
||||
requestingUserToken: z.uuidv4()
|
||||
})
|
||||
|
||||
export const deleteChannelsByCategoryIdSchema = z.object({
|
||||
categoryId: z.uuidv7(),
|
||||
admin: z.boolean(),
|
||||
requestingUserId: z.uuidv7(),
|
||||
requestingUserToken: z.uuidv4()
|
||||
})
|
||||
|
||||
export type CreateChannelInput = z.infer<typeof createChannelSchema>
|
||||
export type GetChannelInput = z.infer<typeof getChannelSchema>
|
||||
export type GetChannelsByCategoryIdInput = z.infer<typeof getChannelsByCategoryIdSchema>
|
||||
export type UpdateChannelInput = z.infer<typeof updateChannelSchema>
|
||||
export type DeleteChannelInput = z.infer<typeof deleteChannelSchema>
|
||||
export type DeleteChannelsByCategoryIdInput = z.infer<typeof deleteChannelsByCategoryIdSchema>
|
||||
@@ -7,7 +7,7 @@ export const queryUserByIdSchema = z.object({
|
||||
export const queryAllUsersByInstanceId = z.object({
|
||||
instanceId: z.uuidv7(),
|
||||
});
|
||||
|
||||
import { is } from 'zod/v4/locales';
|
||||
export const createUserSchema = z.object({
|
||||
username: z.string().min(3).max(30),
|
||||
nickname: z.string().min(1).max(30).optional(),
|
||||
|
||||
Reference in New Issue
Block a user