514 lines
12 KiB
TypeScript
514 lines
12 KiB
TypeScript
import { API_ERROR } from "../../controllers/errors.js";
|
|
import type { Community, Invite, User } from "../../generated/prisma/client.js";
|
|
import { getDB } from "../../store/store.js";
|
|
import {
|
|
getUserFromAuth,
|
|
isUserAllowed,
|
|
isUserOwnerOrAdmin,
|
|
} from "../auth/helpers.js";
|
|
import { PERMISSION } from "../auth/permission.js";
|
|
import { getChannelById } from "../channel/channel.js";
|
|
import { getRoleById } from "../role/role.js";
|
|
import { getUserIdsInCommunity } from "../user/user.js";
|
|
import { SocketMessageTypes } from "../websocket/types.js";
|
|
import { sendMessageToUsersWS } from "../websocket/websocket.js";
|
|
import type {
|
|
ICreateCommunity,
|
|
IUpdateCommunity,
|
|
ICommunityChannel,
|
|
ICommunityMember,
|
|
ICommunityRole,
|
|
ICreateInvite,
|
|
} from "./types.js";
|
|
|
|
const getCommunityById = async (id: string): Promise<Community | null> => {
|
|
return await getDB().community.findUnique({
|
|
where: { id: id },
|
|
});
|
|
};
|
|
|
|
const createCommunity = async (
|
|
ownerId: string,
|
|
create: ICreateCommunity,
|
|
): Promise<Community> => {
|
|
return await getDB().community.create({
|
|
data: {
|
|
ownerId: ownerId,
|
|
...create,
|
|
members: {
|
|
connect: {
|
|
id: ownerId,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
};
|
|
|
|
const createCommunityAuth = async (
|
|
create: ICreateCommunity,
|
|
authHeader: string | undefined,
|
|
): Promise<Community | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
|
|
if (!authUser) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
return await createCommunity(authUser.id, create);
|
|
};
|
|
|
|
const updateCommunityById = async (
|
|
id: string,
|
|
update: IUpdateCommunity,
|
|
): Promise<Community | null> => {
|
|
const updatedCommunity = await getDB().community.update({
|
|
where: {
|
|
id: id,
|
|
},
|
|
data: {
|
|
...update,
|
|
},
|
|
});
|
|
|
|
const userIds = await getUserIdsInCommunity(id);
|
|
|
|
sendMessageToUsersWS(userIds, {
|
|
type: SocketMessageTypes.UPDATE_COMMUNITY,
|
|
payload: {
|
|
communityId: id,
|
|
},
|
|
});
|
|
|
|
return updatedCommunity;
|
|
};
|
|
|
|
const updateCommunityByIdAuth = async (
|
|
id: string,
|
|
update: IUpdateCommunity,
|
|
authHeader: string | undefined,
|
|
): Promise<Community | null | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
const community = await getCommunityById(id);
|
|
|
|
if (
|
|
!(await isUserAllowed(
|
|
authUser,
|
|
{
|
|
community: community,
|
|
},
|
|
community,
|
|
[PERMISSION.COMMUNITY_MANAGE],
|
|
))
|
|
) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
return await updateCommunityById(id, update);
|
|
};
|
|
|
|
const deleteCommunityById = async (id: string): Promise<Community | null> => {
|
|
return await getDB().community.delete({
|
|
where: { id: id },
|
|
});
|
|
};
|
|
|
|
const deleteCommunityByIdAuth = async (
|
|
id: string,
|
|
authHeader: string | undefined,
|
|
): Promise<Community | null | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
const community = await getCommunityById(id);
|
|
|
|
if (
|
|
!(await isUserOwnerOrAdmin(authUser, {
|
|
community: community,
|
|
}))
|
|
) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
return await deleteCommunityById(id);
|
|
};
|
|
|
|
const getCommunityMembersById = async (
|
|
id: string,
|
|
): Promise<ICommunityMember[]> => {
|
|
return await getDB().user.findMany({
|
|
where: {
|
|
communities: {
|
|
some: {
|
|
id: id,
|
|
},
|
|
},
|
|
},
|
|
select: {
|
|
id: true,
|
|
username: true,
|
|
nickname: true,
|
|
avatar: true,
|
|
},
|
|
});
|
|
};
|
|
|
|
const getCommunityMembersByIdAuth = async (
|
|
id: string,
|
|
authHeader: string | undefined,
|
|
): Promise<ICommunityMember[] | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
const community = await getCommunityById(id);
|
|
|
|
if (
|
|
!(await isUserAllowed(
|
|
authUser,
|
|
{
|
|
community: community,
|
|
},
|
|
community,
|
|
[PERMISSION.MEMBERS_READ],
|
|
))
|
|
) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
return await getCommunityMembersById(id);
|
|
};
|
|
|
|
const getCommunityChannelsById = async (
|
|
id: string,
|
|
): Promise<ICommunityChannel[]> => {
|
|
return await getDB().channel.findMany({
|
|
where: {
|
|
communityId: id,
|
|
},
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
description: true,
|
|
category: true,
|
|
order: true,
|
|
},
|
|
});
|
|
};
|
|
|
|
const getCommunityChannelsByIdAuth = async (
|
|
id: string,
|
|
authHeader: string | undefined,
|
|
): Promise<ICommunityChannel[] | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
const community = await getCommunityById(id);
|
|
|
|
if (
|
|
!(await isUserAllowed(
|
|
authUser,
|
|
{
|
|
community: community,
|
|
},
|
|
community,
|
|
[PERMISSION.CHANNELS_READ],
|
|
))
|
|
) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
return await getCommunityChannelsById(id);
|
|
};
|
|
|
|
const getCommunityRolesById = async (id: string): Promise<ICommunityRole[]> => {
|
|
return await getDB().role.findMany({
|
|
where: {
|
|
communityId: id,
|
|
},
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
color: true,
|
|
order: true,
|
|
showInMembers: true,
|
|
},
|
|
});
|
|
};
|
|
|
|
const getCommunityRolesByIdAuth = async (
|
|
id: string,
|
|
authHeader: string | undefined,
|
|
): Promise<ICommunityRole[] | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
const community = await getCommunityById(id);
|
|
|
|
if (
|
|
!(await isUserAllowed(
|
|
authUser,
|
|
{
|
|
community: community,
|
|
},
|
|
community,
|
|
[PERMISSION.ROLES_READ],
|
|
))
|
|
) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
return await getCommunityRolesById(id);
|
|
};
|
|
|
|
const getCommunityInvitesById = async (id: string): Promise<Invite[]> => {
|
|
return await getDB().invite.findMany({
|
|
where: {
|
|
communityId: id,
|
|
},
|
|
});
|
|
};
|
|
|
|
const getCommunityInvitesByIdAuth = async (
|
|
id: string,
|
|
authHeader: string | undefined,
|
|
): Promise<Invite[] | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
const community = await getCommunityById(id);
|
|
|
|
if (
|
|
!(await isUserAllowed(
|
|
authUser,
|
|
{
|
|
community: community,
|
|
},
|
|
community,
|
|
[PERMISSION.INVITES_READ],
|
|
))
|
|
) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
return await getCommunityInvitesById(id);
|
|
};
|
|
|
|
const updateCommunityChannelOrderById = async (id: string, order: string[]) => {
|
|
for (let i = 0; i < order.length; i++) {
|
|
const channelId = order[i];
|
|
if (!channelId) {
|
|
continue;
|
|
}
|
|
|
|
const channel = await getChannelById(channelId);
|
|
if (channel?.communityId !== id) {
|
|
continue;
|
|
}
|
|
|
|
await getDB().channel.update({
|
|
where: {
|
|
id: channelId,
|
|
},
|
|
data: {
|
|
order: i,
|
|
},
|
|
});
|
|
}
|
|
|
|
const userIds = await getUserIdsInCommunity(id);
|
|
|
|
sendMessageToUsersWS(userIds, {
|
|
type: SocketMessageTypes.UPDATE_CHANNELS,
|
|
payload: {
|
|
communityId: id,
|
|
},
|
|
});
|
|
};
|
|
|
|
const updateCommunityChannelOrderByIdAuth = async (
|
|
id: string,
|
|
order: string[],
|
|
authHeader: string | undefined,
|
|
): Promise<void | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
const community = await getCommunityById(id);
|
|
|
|
if (
|
|
!(await isUserAllowed(
|
|
authUser,
|
|
{
|
|
community: community,
|
|
},
|
|
community,
|
|
[PERMISSION.CHANNELS_MANAGE],
|
|
))
|
|
) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
await updateCommunityChannelOrderById(id, order);
|
|
};
|
|
|
|
const updateCommunityRoleOrderById = async (id: string, order: string[]) => {
|
|
for (let i = 0; i < order.length; i++) {
|
|
const roleId = order[i];
|
|
if (!roleId) {
|
|
continue;
|
|
}
|
|
|
|
const role = await getRoleById(roleId);
|
|
if (role?.communityId !== id) {
|
|
continue;
|
|
}
|
|
|
|
await getDB().role.update({
|
|
where: {
|
|
id: roleId,
|
|
},
|
|
data: {
|
|
order: i,
|
|
},
|
|
});
|
|
}
|
|
|
|
const userIds = await getUserIdsInCommunity(id);
|
|
|
|
sendMessageToUsersWS(userIds, {
|
|
type: SocketMessageTypes.UPDATE_ROLES,
|
|
payload: {
|
|
communityId: id,
|
|
},
|
|
});
|
|
};
|
|
|
|
const updateCommunityRoleOrderByIdAuth = async (
|
|
id: string,
|
|
order: string[],
|
|
authHeader: string | undefined,
|
|
): Promise<void | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
const community = await getCommunityById(id);
|
|
|
|
if (
|
|
!(await isUserAllowed(
|
|
authUser,
|
|
{
|
|
community: community,
|
|
},
|
|
community,
|
|
[PERMISSION.ROLES_MANAGE],
|
|
))
|
|
) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
await updateCommunityRoleOrderById(id, order);
|
|
};
|
|
|
|
const createInvite = async (
|
|
id: string,
|
|
creatorId: string,
|
|
createInviteData: ICreateInvite,
|
|
): Promise<Invite> => {
|
|
return await getDB().invite.create({
|
|
data: {
|
|
...createInviteData,
|
|
creatorId: creatorId,
|
|
communityId: id,
|
|
},
|
|
});
|
|
};
|
|
|
|
const createInviteAuth = async (
|
|
id: string,
|
|
createInviteData: ICreateInvite,
|
|
authHeader: string | undefined,
|
|
): Promise<Invite | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
const community = await getCommunityById(id);
|
|
|
|
if (
|
|
!authUser ||
|
|
!(await isUserAllowed(
|
|
authUser,
|
|
{
|
|
community: community,
|
|
},
|
|
community,
|
|
[PERMISSION.INVITES_CREATE],
|
|
))
|
|
) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
return await createInvite(id, authUser.id, createInviteData);
|
|
};
|
|
|
|
const deleteMemberById = async (
|
|
id: string,
|
|
memberId: string,
|
|
): Promise<Community> => {
|
|
const updatedCommunity = await getDB().community.update({
|
|
where: {
|
|
id: id,
|
|
},
|
|
data: {
|
|
members: {
|
|
disconnect: {
|
|
id: memberId,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
const userIds = await getUserIdsInCommunity(updatedCommunity.id);
|
|
|
|
sendMessageToUsersWS(userIds, {
|
|
type: SocketMessageTypes.UPDATE_MEMBERS,
|
|
payload: {
|
|
communityId: updatedCommunity.id,
|
|
},
|
|
});
|
|
|
|
return updatedCommunity;
|
|
};
|
|
|
|
const deleteMemberByIdAuth = async (
|
|
id: string,
|
|
memberId: string,
|
|
authHeader: string | undefined,
|
|
): Promise<Community | API_ERROR.ACCESS_DENIED> => {
|
|
const authUser = await getUserFromAuth(authHeader);
|
|
const community = await getCommunityById(id);
|
|
|
|
if (
|
|
!(await isUserAllowed(
|
|
authUser,
|
|
{
|
|
community: community,
|
|
},
|
|
community,
|
|
[PERMISSION.MEMBERS_KICK],
|
|
)) &&
|
|
authUser?.id !== memberId
|
|
) {
|
|
return API_ERROR.ACCESS_DENIED;
|
|
}
|
|
|
|
return await deleteMemberById(id, memberId);
|
|
};
|
|
|
|
export {
|
|
getCommunityById,
|
|
createCommunity,
|
|
createCommunityAuth,
|
|
updateCommunityById,
|
|
updateCommunityByIdAuth,
|
|
deleteCommunityById,
|
|
deleteCommunityByIdAuth,
|
|
getCommunityMembersById,
|
|
getCommunityMembersByIdAuth,
|
|
getCommunityChannelsById,
|
|
getCommunityChannelsByIdAuth,
|
|
getCommunityRolesById,
|
|
getCommunityRolesByIdAuth,
|
|
getCommunityInvitesById,
|
|
getCommunityInvitesByIdAuth,
|
|
updateCommunityChannelOrderById,
|
|
updateCommunityChannelOrderByIdAuth,
|
|
updateCommunityRoleOrderById,
|
|
updateCommunityRoleOrderByIdAuth,
|
|
createInvite,
|
|
createInviteAuth,
|
|
deleteMemberById,
|
|
deleteMemberByIdAuth,
|
|
};
|