Moved code into src folder. Added build for component library.

This commit is contained in:
Mike Cao 2023-08-21 02:06:09 -07:00
parent 7a7233ead4
commit ede658771e
490 changed files with 749 additions and 442 deletions

180
src/queries/admin/report.ts Normal file
View file

@ -0,0 +1,180 @@
import { Prisma, Report } from '@prisma/client';
import { REPORT_FILTER_TYPES } from 'lib/constants';
import prisma from 'lib/prisma';
import { FilterResult, ReportSearchFilter } from 'lib/types';
export async function createReport(data: Prisma.ReportUncheckedCreateInput): Promise<Report> {
return prisma.client.report.create({ data });
}
export async function getReportById(reportId: string): Promise<Report> {
return prisma.client.report.findUnique({
where: {
id: reportId,
},
});
}
export async function updateReport(
reportId: string,
data: Prisma.ReportUpdateInput,
): Promise<Report> {
return prisma.client.report.update({ where: { id: reportId }, data });
}
export async function deleteReport(reportId: string): Promise<Report> {
return prisma.client.report.delete({ where: { id: reportId } });
}
export async function getReports(
ReportSearchFilter: ReportSearchFilter,
options?: { include?: Prisma.ReportInclude },
): Promise<FilterResult<Report[]>> {
const {
userId,
websiteId,
includeTeams,
filter,
filterType = REPORT_FILTER_TYPES.all,
} = ReportSearchFilter;
const mode = prisma.getSearchMode();
const where: Prisma.ReportWhereInput = {
...(userId && { userId: userId }),
...(websiteId && { websiteId: websiteId }),
AND: [
{
OR: [
{
...(userId && { userId: userId }),
},
{
...(includeTeams && {
website: {
teamWebsite: {
some: {
team: {
teamUser: {
some: {
userId,
},
},
},
},
},
},
}),
},
],
},
{
OR: [
{
...((filterType === REPORT_FILTER_TYPES.all ||
filterType === REPORT_FILTER_TYPES.name) && {
name: {
startsWith: filter,
...mode,
},
}),
},
{
...((filterType === REPORT_FILTER_TYPES.all ||
filterType === REPORT_FILTER_TYPES.description) && {
description: {
startsWith: filter,
...mode,
},
}),
},
{
...((filterType === REPORT_FILTER_TYPES.all ||
filterType === REPORT_FILTER_TYPES.type) && {
type: {
startsWith: filter,
...mode,
},
}),
},
{
...((filterType === REPORT_FILTER_TYPES.all ||
filterType === REPORT_FILTER_TYPES['user:username']) && {
user: {
username: {
startsWith: filter,
...mode,
},
},
}),
},
{
...((filterType === REPORT_FILTER_TYPES.all ||
filterType === REPORT_FILTER_TYPES['website:name']) && {
website: {
name: {
startsWith: filter,
...mode,
},
},
}),
},
{
...((filterType === REPORT_FILTER_TYPES.all ||
filterType === REPORT_FILTER_TYPES['website:domain']) && {
website: {
domain: {
startsWith: filter,
...mode,
},
},
}),
},
],
},
],
};
const [pageFilters, getParameters] = prisma.getPageFilters(ReportSearchFilter);
const reports = await prisma.client.report.findMany({
where,
...pageFilters,
...(options?.include && { include: options.include }),
});
const count = await prisma.client.report.count({
where,
});
return {
data: reports,
count,
...getParameters,
};
}
export async function getReportsByUserId(
userId: string,
filter: ReportSearchFilter,
): Promise<FilterResult<Report[]>> {
return getReports(
{ userId, ...filter },
{
include: {
website: {
select: {
domain: true,
userId: true,
},
},
},
},
);
}
export async function getReportsByWebsiteId(
websiteId: string,
filter: ReportSearchFilter,
): Promise<FilterResult<Report[]>> {
return getReports({ websiteId, ...filter });
}

164
src/queries/admin/team.ts Normal file
View file

@ -0,0 +1,164 @@
import { Prisma, Team } from '@prisma/client';
import { ROLES, TEAM_FILTER_TYPES } from 'lib/constants';
import { uuid } from 'lib/crypto';
import prisma from 'lib/prisma';
import { FilterResult, TeamSearchFilter } from 'lib/types';
export interface GetTeamOptions {
includeTeamUser?: boolean;
}
async function getTeam(where: Prisma.TeamWhereInput, options: GetTeamOptions = {}): Promise<Team> {
const { includeTeamUser = false } = options;
return prisma.client.team.findFirst({
where,
include: {
teamUser: includeTeamUser,
},
});
}
export function getTeamById(teamId: string, options: GetTeamOptions = {}) {
return getTeam({ id: teamId }, options);
}
export function getTeamByAccessCode(accessCode: string, options: GetTeamOptions = {}) {
return getTeam({ accessCode }, options);
}
export async function createTeam(data: Prisma.TeamCreateInput, userId: string): Promise<Team> {
const { id } = data;
return prisma.transaction([
prisma.client.team.create({
data,
}),
prisma.client.teamUser.create({
data: {
id: uuid(),
teamId: id,
userId,
role: ROLES.teamOwner,
},
}),
]);
}
export async function updateTeam(teamId: string, data: Prisma.TeamUpdateInput): Promise<Team> {
return prisma.client.team.update({
where: {
id: teamId,
},
data: {
...data,
updatedAt: new Date(),
},
});
}
export async function deleteTeam(
teamId: string,
): Promise<Promise<[Prisma.BatchPayload, Prisma.BatchPayload, Team]>> {
const { client, transaction } = prisma;
return transaction([
client.teamWebsite.deleteMany({
where: {
teamId,
},
}),
client.teamUser.deleteMany({
where: {
teamId,
},
}),
client.team.delete({
where: {
id: teamId,
},
}),
]);
}
export async function getTeams(
TeamSearchFilter: TeamSearchFilter,
options?: { include?: Prisma.TeamInclude },
): Promise<FilterResult<Team[]>> {
const { userId, filter, filterType = TEAM_FILTER_TYPES.all } = TeamSearchFilter;
const mode = prisma.getSearchMode();
const where: Prisma.TeamWhereInput = {
...(userId && {
teamUser: {
some: { userId },
},
}),
...(filter && {
AND: {
OR: [
{
...((filterType === TEAM_FILTER_TYPES.all || filterType === TEAM_FILTER_TYPES.name) && {
name: { startsWith: filter, ...mode },
}),
},
{
...((filterType === TEAM_FILTER_TYPES.all ||
filterType === TEAM_FILTER_TYPES['user:username']) && {
teamUser: {
some: {
role: ROLES.teamOwner,
user: {
username: {
startsWith: filter,
...mode,
},
},
},
},
}),
},
],
},
}),
};
const [pageFilters, getParameters] = prisma.getPageFilters({
orderBy: 'name',
...TeamSearchFilter,
});
const teams = await prisma.client.team.findMany({
where: {
...where,
},
...pageFilters,
...(options?.include && { include: options?.include }),
});
const count = await prisma.client.team.count({ where });
return { data: teams, count, ...getParameters };
}
export async function getTeamsByUserId(
userId: string,
filter?: TeamSearchFilter,
): Promise<FilterResult<Team[]>> {
return getTeams(
{ userId, ...filter },
{
include: {
teamUser: {
include: {
user: {
select: {
id: true,
username: true,
},
},
},
},
},
},
);
}

View file

@ -0,0 +1,98 @@
import { Prisma, TeamUser } from '@prisma/client';
import { uuid } from 'lib/crypto';
import prisma from 'lib/prisma';
export async function getTeamUserById(teamUserId: string): Promise<TeamUser> {
return prisma.client.teamUser.findUnique({
where: {
id: teamUserId,
},
});
}
export async function getTeamUser(teamId: string, userId: string): Promise<TeamUser> {
return prisma.client.teamUser.findFirst({
where: {
teamId,
userId,
},
});
}
export async function getTeamUsers(
teamId: string,
): Promise<(TeamUser & { user: { id: string; username: string } })[]> {
return prisma.client.teamUser.findMany({
where: {
teamId,
},
include: {
user: {
select: {
id: true,
username: true,
},
},
},
});
}
export async function createTeamUser(
userId: string,
teamId: string,
role: string,
): Promise<TeamUser> {
return prisma.client.teamUser.create({
data: {
id: uuid(),
userId,
teamId,
role,
},
});
}
export async function updateTeamUser(
teamUserId: string,
data: Prisma.TeamUserUpdateInput,
): Promise<TeamUser> {
return prisma.client.teamUser.update({
where: {
id: teamUserId,
},
data,
});
}
export async function deleteTeamUser(teamId: string, userId: string): Promise<TeamUser> {
const { client, transaction } = prisma;
return transaction([
client.teamWebsite.deleteMany({
where: {
teamId: teamId,
website: {
userId: userId,
},
},
}),
client.teamUser.deleteMany({
where: {
teamId,
userId,
},
}),
]);
}
export async function deleteTeamUserByUserId(
userId: string,
teamId: string,
): Promise<Prisma.BatchPayload> {
return prisma.client.teamUser.deleteMany({
where: {
userId,
teamId,
},
});
}

View file

@ -0,0 +1,127 @@
import { Prisma, Team, TeamUser, TeamWebsite, Website } from '@prisma/client';
import { ROLES } from 'lib/constants';
import { uuid } from 'lib/crypto';
import prisma from 'lib/prisma';
export async function getTeamWebsite(
teamId: string,
websiteId: string,
): Promise<
TeamWebsite & {
website: Website;
}
> {
return prisma.client.teamWebsite.findFirst({
where: {
teamId,
websiteId,
},
include: {
website: true,
},
});
}
export async function findTeamWebsiteByUserId(
websiteId: string,
userId: string,
): Promise<TeamWebsite> {
return prisma.client.teamWebsite.findFirst({
where: {
websiteId,
team: {
teamUser: {
some: {
userId,
},
},
},
},
});
}
export async function getTeamWebsites(teamId: string): Promise<
(TeamWebsite & {
team: Team & { teamUser: TeamUser[] };
website: Website & {
user: { id: string; username: string };
};
})[]
> {
return prisma.client.teamWebsite.findMany({
where: {
teamId,
},
include: {
team: {
include: {
teamUser: {
where: {
role: ROLES.teamOwner,
},
},
},
},
website: {
include: {
user: {
select: {
id: true,
username: true,
},
},
},
},
},
orderBy: [
{
team: {
name: 'asc',
},
},
],
});
}
export async function createTeamWebsite(teamId: string, websiteId: string): Promise<TeamWebsite> {
return prisma.client.teamWebsite.create({
data: {
id: uuid(),
teamId,
websiteId,
},
});
}
export async function createTeamWebsites(teamId: string, websiteIds: string[]) {
const currentTeamWebsites = await getTeamWebsites(teamId);
// filter out websites that already exists on the team
const addWebsites = websiteIds.filter(
websiteId => !currentTeamWebsites.some(a => a.websiteId === websiteId),
);
const teamWebsites: Prisma.TeamWebsiteCreateManyInput[] = addWebsites.map(a => {
return {
id: uuid(),
teamId,
websiteId: a,
};
});
return prisma.client.teamWebsite.createMany({
data: teamWebsites,
});
}
export async function deleteTeamWebsite(
teamId: string,
websiteId: string,
): Promise<Prisma.BatchPayload> {
return prisma.client.teamWebsite.deleteMany({
where: {
teamId,
websiteId,
},
});
}

284
src/queries/admin/user.ts Normal file
View file

@ -0,0 +1,284 @@
import { Prisma } from '@prisma/client';
import cache from 'lib/cache';
import { ROLES, USER_FILTER_TYPES } from 'lib/constants';
import prisma from 'lib/prisma';
import { FilterResult, Role, User, UserSearchFilter } from 'lib/types';
import { getRandomChars } from 'next-basics';
export interface GetUserOptions {
includePassword?: boolean;
showDeleted?: boolean;
}
async function getUser(
where: Prisma.UserWhereInput | Prisma.UserWhereUniqueInput,
options: GetUserOptions = {},
): Promise<User> {
const { includePassword = false, showDeleted = false } = options;
return prisma.client.user.findFirst({
where: { ...where, ...(showDeleted ? {} : { deletedAt: null }) },
select: {
id: true,
username: true,
password: includePassword,
role: true,
createdAt: true,
},
});
}
export async function getUserById(userId: string, options: GetUserOptions = {}) {
return getUser({ id: userId }, options);
}
export async function getUserByUsername(username: string, options: GetUserOptions = {}) {
return getUser({ username }, options);
}
export async function getUsers(
searchFilter: UserSearchFilter,
options?: { include?: Prisma.UserInclude },
): Promise<FilterResult<User[]>> {
const { teamId, filter, filterType = USER_FILTER_TYPES.all } = searchFilter;
const mode = prisma.getSearchMode();
const where: Prisma.UserWhereInput = {
...(teamId && {
teamUser: {
some: {
teamId,
},
},
}),
...(filter && {
AND: {
OR: [
{
...((filterType === USER_FILTER_TYPES.all ||
filterType === USER_FILTER_TYPES.username) && {
username: {
startsWith: filter,
...mode,
},
}),
},
],
},
}),
};
const [pageFilters, getParameters] = prisma.getPageFilters({
orderBy: 'username',
...searchFilter,
});
const users = await prisma.client.user
.findMany({
where: {
...where,
deletedAt: null,
},
...pageFilters,
...(options?.include && { include: options.include }),
})
.then(a => {
return a.map(({ password, ...rest }) => rest);
});
const count = await prisma.client.user.count({
where: {
...where,
deletedAt: null,
},
});
return { data: users as any, count, ...getParameters };
}
export async function getUsersByTeamId(teamId: string, filter?: UserSearchFilter) {
return getUsers({ teamId, ...filter });
}
export async function createUser(data: {
id: string;
username: string;
password: string;
role: Role;
}): Promise<{
id: string;
username: string;
role: string;
}> {
return prisma.client.user.create({
data,
select: {
id: true,
username: true,
role: true,
},
});
}
export async function updateUser(
data: Prisma.UserUpdateInput,
where: Prisma.UserWhereUniqueInput,
): Promise<User> {
return prisma.client.user.update({
where,
data,
select: {
id: true,
username: true,
role: true,
createdAt: true,
},
});
}
export async function deleteUser(
userId: string,
): Promise<
[
Prisma.BatchPayload,
Prisma.BatchPayload,
Prisma.BatchPayload,
Prisma.BatchPayload,
Prisma.BatchPayload,
Prisma.BatchPayload,
User,
]
> {
const { client } = prisma;
const cloudMode = process.env.CLOUD_MODE;
const websites = await client.website.findMany({
where: { userId },
});
let websiteIds = [];
if (websites.length > 0) {
websiteIds = websites.map(a => a.id);
}
const teams = await client.team.findMany({
where: {
teamUser: {
some: {
userId,
role: ROLES.teamOwner,
},
},
},
});
const teamIds = teams.map(a => a.id);
return prisma
.transaction([
client.eventData.deleteMany({
where: { websiteId: { in: websiteIds } },
}),
client.websiteEvent.deleteMany({
where: { websiteId: { in: websiteIds } },
}),
client.session.deleteMany({
where: { websiteId: { in: websiteIds } },
}),
client.teamWebsite.deleteMany({
where: {
OR: [
{
websiteId: {
in: websiteIds,
},
},
{
teamId: {
in: teamIds,
},
},
],
},
}),
client.teamWebsite.deleteMany({
where: {
teamId: {
in: teamIds,
},
},
}),
client.teamUser.deleteMany({
where: {
OR: [
{
teamId: {
in: teamIds,
},
},
{
userId,
},
],
},
}),
client.team.deleteMany({
where: {
id: {
in: teamIds,
},
},
}),
client.report.deleteMany({
where: {
OR: [
{
websiteId: {
in: websiteIds,
},
},
{
userId,
},
],
},
}),
cloudMode
? client.website.updateMany({
data: {
deletedAt: new Date(),
},
where: { id: { in: websiteIds } },
})
: client.website.deleteMany({
where: { id: { in: websiteIds } },
}),
cloudMode
? client.user.update({
data: {
username: getRandomChars(32),
deletedAt: new Date(),
},
where: {
id: userId,
},
})
: client.user.delete({
where: {
id: userId,
},
}),
])
.then(async data => {
if (cache.enabled) {
const ids = websites.map(a => a.id);
for (let i = 0; i < ids.length; i++) {
await cache.deleteWebsite(`website:${ids[i]}`);
}
}
return data;
});
}

View file

@ -0,0 +1,349 @@
import { Prisma, Website } from '@prisma/client';
import cache from 'lib/cache';
import { ROLES, WEBSITE_FILTER_TYPES } from 'lib/constants';
import prisma from 'lib/prisma';
import { FilterResult, WebsiteSearchFilter } from 'lib/types';
async function getWebsite(where: Prisma.WebsiteWhereUniqueInput): Promise<Website> {
return prisma.client.website.findUnique({
where,
});
}
export async function getWebsiteById(id: string) {
return getWebsite({ id });
}
export async function getWebsiteByShareId(shareId: string) {
return getWebsite({ shareId });
}
export async function getWebsites(
WebsiteSearchFilter: WebsiteSearchFilter,
options?: { include?: Prisma.WebsiteInclude },
): Promise<FilterResult<Website[]>> {
const {
userId,
teamId,
includeTeams,
onlyTeams,
filter,
filterType = WEBSITE_FILTER_TYPES.all,
} = WebsiteSearchFilter;
const mode = prisma.getSearchMode();
const where: Prisma.WebsiteWhereInput = {
...(teamId && {
teamWebsite: {
some: {
teamId,
},
},
}),
AND: [
{
OR: [
{
...(userId &&
!onlyTeams && {
userId,
}),
},
{
...((includeTeams || onlyTeams) && {
AND: [
{
teamWebsite: {
some: {
team: {
teamUser: {
some: {
userId,
},
},
},
},
},
},
{
userId: {
not: userId,
},
},
],
}),
},
],
},
{
OR: [
{
...((filterType === WEBSITE_FILTER_TYPES.all ||
filterType === WEBSITE_FILTER_TYPES.name) && {
name: { startsWith: filter, ...mode },
}),
},
{
...((filterType === WEBSITE_FILTER_TYPES.all ||
filterType === WEBSITE_FILTER_TYPES.domain) && {
domain: { startsWith: filter, ...mode },
}),
},
],
},
],
};
const [pageFilters, getParameters] = prisma.getPageFilters({
orderBy: 'name',
...WebsiteSearchFilter,
});
const websites = await prisma.client.website.findMany({
where: {
...where,
deletedAt: null,
},
...pageFilters,
...(options?.include && { include: options.include }),
});
const count = await prisma.client.website.count({ where });
return { data: websites, count, ...getParameters };
}
export async function getWebsitesByUserId(
userId: string,
filter?: WebsiteSearchFilter,
): Promise<FilterResult<Website[]>> {
return getWebsites(
{ userId, ...filter },
{
include: {
teamWebsite: {
include: {
team: {
select: {
name: true,
},
},
},
},
user: {
select: {
username: true,
id: true,
},
},
},
},
);
}
export async function getWebsitesByTeamId(
teamId: string,
filter?: WebsiteSearchFilter,
): Promise<FilterResult<Website[]>> {
return getWebsites(
{
teamId,
...filter,
includeTeams: true,
},
{
include: {
teamWebsite: {
include: {
team: {
include: {
teamUser: {
where: { role: ROLES.teamOwner },
},
},
},
},
},
user: {
select: {
id: true,
username: true,
},
},
},
},
);
}
export async function getUserWebsites(
userId: string,
options?: { includeTeams: boolean },
): Promise<Website[]> {
const { rawQuery } = prisma;
if (options?.includeTeams) {
const websites = await rawQuery(
`
select
website_id as "id",
name,
domain,
share_id as "shareId",
reset_at as "resetAt",
user_id as "userId",
created_at as "createdAt",
updated_at as "updatedAt",
deleted_at as "deletedAt",
null as "teamId",
null as "teamName"
from website
where user_id = {{userId::uuid}}
and deleted_at is null
union
select
w.website_id as "id",
w.name,
w.domain,
w.share_id as "shareId",
w.reset_at as "resetAt",
w.user_id as "userId",
w.created_at as "createdAt",
w.updated_at as "updatedAt",
w.deleted_at as "deletedAt",
t.team_id as "teamId",
t.name as "teamName"
from website w
inner join team_website tw
on tw.website_id = w.website_id
inner join team t
on t.team_id = tw.team_id
inner join team_user tu
on tu.team_id = tw.team_id
where tu.user_id = {{userId::uuid}}
and w.deleted_at is null
`,
{ userId },
);
return websites.reduce((arr, item) => {
if (!arr.find(({ id }) => id === item.id)) {
return arr.concat(item);
}
return arr;
}, []);
}
return prisma.client.website.findMany({
where: {
userId,
deletedAt: null,
},
orderBy: [
{
name: 'asc',
},
],
});
}
export async function createWebsite(
data: Prisma.WebsiteCreateInput | Prisma.WebsiteUncheckedCreateInput,
): Promise<Website> {
return prisma.client.website
.create({
data,
})
.then(async data => {
if (cache.enabled) {
await cache.storeWebsite(data);
}
return data;
});
}
export async function updateWebsite(
websiteId,
data: Prisma.WebsiteUpdateInput | Prisma.WebsiteUncheckedUpdateInput,
): Promise<Website> {
return prisma.client.website.update({
where: {
id: websiteId,
},
data,
});
}
export async function resetWebsite(
websiteId,
): Promise<[Prisma.BatchPayload, Prisma.BatchPayload, Website]> {
const { client, transaction } = prisma;
return transaction([
client.eventData.deleteMany({
where: { websiteId },
}),
client.websiteEvent.deleteMany({
where: { websiteId },
}),
client.session.deleteMany({
where: { websiteId },
}),
client.website.update({
where: { id: websiteId },
data: {
resetAt: new Date(),
},
}),
]).then(async data => {
if (cache.enabled) {
await cache.storeWebsite(data[2]);
}
return data;
});
}
export async function deleteWebsite(
websiteId,
): Promise<[Prisma.BatchPayload, Prisma.BatchPayload, Website]> {
const { client, transaction } = prisma;
const cloudMode = process.env.CLOUD_MODE;
return transaction([
client.eventData.deleteMany({
where: { websiteId },
}),
client.websiteEvent.deleteMany({
where: { websiteId },
}),
client.session.deleteMany({
where: { websiteId },
}),
client.teamWebsite.deleteMany({
where: {
websiteId,
},
}),
client.report.deleteMany({
where: {
websiteId,
},
}),
cloudMode
? prisma.client.website.update({
data: {
deletedAt: new Date(),
},
where: { id: websiteId },
})
: client.website.delete({
where: { id: websiteId },
}),
]).then(async data => {
if (cache.enabled) {
await cache.deleteWebsite(websiteId);
}
return data;
});
}