Files
umami/src/permissions/website.ts
T

224 lines
4.8 KiB
TypeScript

import { hasPermission } from '@/lib/auth';
import { PERMISSIONS } from '@/lib/constants';
import { getEntity } from '@/lib/entity';
import prisma from '@/lib/prisma';
import type { Auth } from '@/lib/types';
import { getTeamUser, getWebsite } from '@/queries/prisma';
export async function canViewWebsite({ user, shareToken }: Auth, websiteId: string) {
if (user?.isAdmin) {
return true;
}
if (
shareToken?.websiteId === websiteId ||
shareToken?.pixelId === websiteId ||
shareToken?.linkId === websiteId ||
shareToken?.websiteIds?.includes(websiteId) ||
shareToken?.pixelIds?.includes(websiteId) ||
shareToken?.linkIds?.includes(websiteId)
) {
return true;
}
const entity = await getEntity(websiteId);
if (!entity || !user) {
return false;
}
if (entity.userId) {
return user.id === entity.userId;
}
if (entity.teamId) {
const teamUser = await getTeamUser(entity.teamId, user.id);
return !!teamUser;
}
return false;
}
export async function canViewBatchWebsites({ user, shareToken }: Auth, websiteIds: string[]) {
if (!websiteIds.length) {
return [];
}
const requestedIds = Array.from(new Set(websiteIds));
if (user?.isAdmin) {
return requestedIds;
}
const shareAllowedIds = new Set(
[
shareToken?.websiteId,
shareToken?.pixelId,
shareToken?.linkId,
...(shareToken?.websiteIds ?? []),
...(shareToken?.pixelIds ?? []),
...(shareToken?.linkIds ?? []),
].filter((id): id is string => Boolean(id)),
);
if (!user) {
return requestedIds.filter(id => shareAllowedIds.has(id));
}
const websites = await prisma.client.website.findMany({
where: {
id: {
in: requestedIds,
},
},
select: {
id: true,
userId: true,
teamId: true,
},
});
const ownedIds = new Set(
websites.filter(website => website.userId === user.id).map(website => website.id),
);
const teamIds = Array.from(
new Set(websites.map(website => website.teamId).filter((teamId): teamId is string => Boolean(teamId))),
);
const teamUsers = teamIds.length
? await prisma.client.teamUser.findMany({
where: {
userId: user.id,
teamId: {
in: teamIds,
},
},
select: {
teamId: true,
},
})
: [];
const allowedTeamIds = new Set(teamUsers.map(teamUser => teamUser.teamId));
const teamOwnedIds = new Set(
websites
.filter(website => website.teamId && allowedTeamIds.has(website.teamId))
.map(website => website.id),
);
return requestedIds.filter(
id => shareAllowedIds.has(id) || ownedIds.has(id) || teamOwnedIds.has(id),
);
}
export async function canViewAllWebsites({ user }: Auth) {
return user?.isAdmin ?? false;
}
export async function canCreateWebsite({ user }: Auth) {
if (!user) {
return false;
}
if (user.isAdmin) {
return true;
}
return hasPermission(user.role, PERMISSIONS.websiteCreate);
}
export async function canUpdateWebsite({ user }: Auth, websiteId: string) {
if (!user) {
return false;
}
if (user.isAdmin) {
return true;
}
const website = await getWebsite(websiteId);
if (!website) {
return false;
}
if (website.userId) {
return user.id === website.userId;
}
if (website.teamId) {
const teamUser = await getTeamUser(website.teamId, user.id);
return teamUser && hasPermission(teamUser.role, PERMISSIONS.websiteUpdate);
}
return false;
}
export async function canDeleteWebsite({ user }: Auth, websiteId: string) {
if (!user) {
return false;
}
if (user.isAdmin) {
return true;
}
const website = await getWebsite(websiteId);
if (!website) {
return false;
}
if (website.userId) {
return user.id === website.userId;
}
if (website.teamId) {
const teamUser = await getTeamUser(website.teamId, user.id);
return teamUser && hasPermission(teamUser.role, PERMISSIONS.websiteDelete);
}
return false;
}
export async function canTransferWebsiteToUser({ user }: Auth, websiteId: string, userId: string) {
if (!user) {
return false;
}
const website = await getWebsite(websiteId);
if (!website) {
return false;
}
if (website.teamId && user.id === userId) {
const teamUser = await getTeamUser(website.teamId, userId);
return teamUser && hasPermission(teamUser.role, PERMISSIONS.websiteTransferToUser);
}
return false;
}
export async function canTransferWebsiteToTeam({ user }: Auth, websiteId: string, teamId: string) {
if (!user) {
return false;
}
const website = await getWebsite(websiteId);
if (!website) {
return false;
}
if (website.userId && website.userId === user.id) {
const teamUser = await getTeamUser(teamId, user.id);
return teamUser && hasPermission(teamUser.role, PERMISSIONS.websiteTransferToTeam);
}
return false;
}