snapify-authentik/src/server/api/routers/video.ts
2023-05-03 21:35:58 +02:00

358 lines
9.1 KiB
TypeScript

import { z } from "zod";
import {
createTRPCRouter,
protectedProcedure,
publicProcedure,
} from "~/server/api/trpc";
import {
DeleteObjectCommand,
GetObjectCommand,
PutObjectCommand,
} from "@aws-sdk/client-s3";
import { env } from "~/env.mjs";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { TRPCError } from "@trpc/server";
export const videoRouter = createTRPCRouter({
getAll: protectedProcedure.query(
async ({ ctx: { prisma, session, s3, posthog } }) => {
const videos = await prisma.video.findMany({
where: {
userId: session.user.id,
},
});
posthog?.capture({
distinctId: session.user.id,
event: "viewing video list",
properties: {
videoAmount: videos.length,
},
});
void posthog?.shutdownAsync();
const videosWithThumbnailUrl = await Promise.all(
videos.map(async (video) => {
const thumbnailUrl = await getSignedUrl(
s3,
new GetObjectCommand({
Bucket: env.AWS_BUCKET_NAME,
Key: video.userId + "/" + video.id + "-thumbnail",
})
);
return { ...video, thumbnailUrl };
})
);
return videosWithThumbnailUrl;
}
),
get: publicProcedure
.input(z.object({ videoId: z.string() }))
.query(async ({ ctx, input }) => {
const { s3, posthog, session, prisma } = ctx;
const video = await prisma.video.findUnique({
where: {
id: input.videoId,
},
include: {
user: true,
},
});
if (!video) {
throw new TRPCError({ code: "NOT_FOUND" });
}
if (video.userId !== session?.user.id && !video.sharing) {
throw new TRPCError({ code: "FORBIDDEN" });
}
if (session) {
posthog?.capture({
distinctId: session.user.id,
event: "viewing video",
properties: {
videoId: video.id,
videoCreatedAt: video.createdAt,
videoUpdatedAt: video.updatedAt,
videoUser: video.user.id,
videoSharing: video.sharing,
videoDeleteAfterLinkExpires: video.delete_after_link_expires,
videoShareLinkExpiresAt: video.shareLinkExpiresAt,
},
});
void posthog?.shutdownAsync();
}
const getObjectCommand = new GetObjectCommand({
Bucket: env.AWS_BUCKET_NAME,
Key: video.userId + "/" + video.id,
});
const signedUrl = await getSignedUrl(s3, getObjectCommand);
return { ...video, video_url: signedUrl };
}),
getUploadUrl: protectedProcedure
.input(z.object({ key: z.string() }))
.mutation(async ({ ctx: { prisma, session, s3, posthog }, input }) => {
const { key } = input;
const videos = await prisma.video.findMany({
where: {
userId: session.user.id,
},
});
if (
videos.length >= 10 &&
session.user.stripeSubscriptionStatus !== "active"
) {
posthog?.capture({
distinctId: session.user.id,
event: "hit video upload limit",
properties: {
videoAmount: videos.length,
stripeSubscriptionStatus: session.user.stripeSubscriptionStatus,
},
});
void posthog?.shutdownAsync();
throw new TRPCError({
code: "FORBIDDEN",
message:
"Sorry, you have reached the maximum video upload limit on our free tier. Please upgrade to upload more.",
});
}
posthog?.capture({
distinctId: session.user.id,
event: "uploading video",
properties: {
videoAmount: videos.length,
stripeSubscriptionStatus: session.user.stripeSubscriptionStatus,
},
});
void posthog?.shutdownAsync();
const video = await prisma.video.create({
data: {
userId: session.user.id,
title: key,
},
});
const signedVideoUrl = await getSignedUrl(
s3,
new PutObjectCommand({
Bucket: env.AWS_BUCKET_NAME,
Key: session.user.id + "/" + video.id,
})
);
const signedThumbnailUrl = await getSignedUrl(
s3,
new PutObjectCommand({
Bucket: env.AWS_BUCKET_NAME,
Key: video.userId + "/" + video.id + "-thumbnail",
})
);
return {
success: true,
id: video.id,
signedVideoUrl,
signedThumbnailUrl,
};
}),
setSharing: protectedProcedure
.input(z.object({ videoId: z.string(), sharing: z.boolean() }))
.mutation(async ({ ctx: { prisma, session, posthog }, input }) => {
const updateVideo = await prisma.video.updateMany({
where: {
id: input.videoId,
userId: session.user.id,
},
data: {
sharing: input.sharing,
},
});
if (updateVideo.count === 0) {
throw new TRPCError({ code: "FORBIDDEN" });
}
posthog?.capture({
distinctId: session.user.id,
event: "update video setSharing",
properties: {
videoId: input.videoId,
videoSharing: input.sharing,
},
});
void posthog?.shutdownAsync();
return {
success: true,
updateVideo,
};
}),
setDeleteAfterLinkExpires: protectedProcedure
.input(
z.object({ videoId: z.string(), delete_after_link_expires: z.boolean() })
)
.mutation(async ({ ctx: { prisma, session, posthog }, input }) => {
const updateVideo = await prisma.video.updateMany({
where: {
id: input.videoId,
userId: session.user.id,
},
data: {
delete_after_link_expires: input.delete_after_link_expires,
},
});
if (updateVideo.count === 0) {
throw new TRPCError({ code: "FORBIDDEN" });
}
posthog?.capture({
distinctId: session.user.id,
event: "update video delete_after_link_expires",
properties: {
videoId: input.videoId,
delete_after_link_expires: input.delete_after_link_expires,
},
});
void posthog?.shutdownAsync();
return {
success: true,
updateVideo,
};
}),
setShareLinkExpiresAt: protectedProcedure
.input(
z.object({
videoId: z.string(),
shareLinkExpiresAt: z.nullable(z.date()),
})
)
.mutation(async ({ ctx: { prisma, session, posthog }, input }) => {
const updateVideo = await prisma.video.updateMany({
where: {
id: input.videoId,
userId: session.user.id,
},
data: {
shareLinkExpiresAt: input.shareLinkExpiresAt,
},
});
if (updateVideo.count === 0) {
throw new TRPCError({ code: "FORBIDDEN" });
}
posthog?.capture({
distinctId: session.user.id,
event: "update video shareLinkExpiresAt",
properties: {
videoId: input.videoId,
shareLinkExpiresAt: input.shareLinkExpiresAt,
},
});
void posthog?.shutdownAsync();
return {
success: true,
updateVideo,
};
}),
renameVideo: protectedProcedure
.input(
z.object({
videoId: z.string(),
title: z.string(),
})
)
.mutation(async ({ ctx: { prisma, session, posthog }, input }) => {
const updateVideo = await prisma.video.updateMany({
where: {
id: input.videoId,
userId: session.user.id,
},
data: {
title: input.title,
},
});
if (updateVideo.count === 0) {
throw new TRPCError({ code: "FORBIDDEN" });
}
posthog?.capture({
distinctId: session.user.id,
event: "update video title",
properties: {
videoId: input.videoId,
title: input.title,
},
});
void posthog?.shutdownAsync();
return {
success: true,
updateVideo,
};
}),
deleteVideo: protectedProcedure
.input(
z.object({
videoId: z.string(),
})
)
.mutation(async ({ ctx: { prisma, session, s3, posthog }, input }) => {
const deleteVideo = await prisma.video.deleteMany({
where: {
id: input.videoId,
userId: session.user.id,
},
});
if (deleteVideo.count === 0) {
throw new TRPCError({ code: "FORBIDDEN" });
}
posthog?.capture({
distinctId: session.user.id,
event: "video delete",
properties: {
videoId: input.videoId,
},
});
void posthog?.shutdownAsync();
const deleteVideoObject = await s3.send(
new DeleteObjectCommand({
Bucket: env.AWS_BUCKET_NAME,
Key: session.user.id + "/" + input.videoId,
})
);
const deleteThumbnailObject = await s3.send(
new DeleteObjectCommand({
Bucket: env.AWS_BUCKET_NAME,
Key: session.user.id + "/" + input.videoId + "-thumbnail",
})
);
return {
success: true,
deleteVideo,
deleteVideoObject,
deleteThumbnailObject,
};
}),
});