287 lines
7.5 KiB
TypeScript
287 lines
7.5 KiB
TypeScript
import type { Prisma, Project as ProjectType } from '@prisma/client'
|
|
import type { ResolverArgs } from '@redwoodjs/api'
|
|
import { uploadImage, makeSocialPublicIdServer } from 'src/lib/cloudinary'
|
|
|
|
import { db } from 'src/lib/db'
|
|
import {
|
|
foreignKeyReplacement,
|
|
enforceAlphaNumeric,
|
|
generateUniqueString,
|
|
generateUniqueStringWithoutSeed,
|
|
destroyImage,
|
|
} from 'src/services/helpers'
|
|
import { requireAuth } from 'src/lib/auth'
|
|
import { requireOwnership, requireProjectOwnership } from 'src/lib/owner'
|
|
|
|
export const projects = ({ userName }) => {
|
|
if (!userName) {
|
|
return db.project.findMany({ where: { deleted: false } })
|
|
}
|
|
return db.project.findMany({
|
|
where: {
|
|
deleted: false,
|
|
user: {
|
|
userName,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
export const project = ({ id }: Prisma.ProjectWhereUniqueInput) => {
|
|
return db.project.findUnique({
|
|
where: { id },
|
|
})
|
|
}
|
|
export const projectByUserAndTitle = async ({ userName, projectTitle }) => {
|
|
const user = await db.user.findUnique({
|
|
where: {
|
|
userName,
|
|
},
|
|
})
|
|
return db.project.findUnique({
|
|
where: {
|
|
title_userId: {
|
|
title: projectTitle,
|
|
userId: user.id,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
const isUniqueProjectTitle = (userId: string) => async (seed: string) =>
|
|
db.project.findUnique({
|
|
where: {
|
|
title_userId: {
|
|
title: seed,
|
|
userId,
|
|
},
|
|
},
|
|
})
|
|
|
|
interface CreateProjectArgs {
|
|
input: Prisma.ProjectCreateArgs['data']
|
|
}
|
|
|
|
export const createProject = async ({ input }: CreateProjectArgs) => {
|
|
requireAuth()
|
|
console.log(input.userId)
|
|
const isUniqueCallback = isUniqueProjectTitle(input.userId)
|
|
let title = input.title
|
|
if (!title) {
|
|
title = await generateUniqueStringWithoutSeed(isUniqueCallback)
|
|
}
|
|
return db.project.create({
|
|
data: foreignKeyReplacement({
|
|
...input,
|
|
title,
|
|
}),
|
|
})
|
|
}
|
|
|
|
export const forkProject = async ({ input }) => {
|
|
requireAuth()
|
|
const projectData = await db.project.findUnique({
|
|
where: {
|
|
id: input.forkedFromId,
|
|
},
|
|
})
|
|
const isUniqueCallback = isUniqueProjectTitle(input.userId)
|
|
let title = projectData.title
|
|
|
|
title = await generateUniqueString(title, isUniqueCallback)
|
|
|
|
const { code, description, cadPackage } = projectData
|
|
|
|
return db.project.create({
|
|
data: foreignKeyReplacement({
|
|
...input,
|
|
title,
|
|
code,
|
|
description,
|
|
cadPackage,
|
|
}),
|
|
})
|
|
}
|
|
|
|
interface UpdateProjectArgs extends Prisma.ProjectWhereUniqueInput {
|
|
input: Prisma.ProjectUpdateInput
|
|
}
|
|
|
|
export const updateProject = async ({ id, input }: UpdateProjectArgs) => {
|
|
const checkSocialCardValidity = async (
|
|
projectId: string,
|
|
input: UpdateProjectArgs['input'],
|
|
oldProject: ProjectType
|
|
) => {
|
|
const titleChange = input.title && input.title !== oldProject.title
|
|
const descriptionChange =
|
|
input.description && input.description !== oldProject.description
|
|
if (titleChange || descriptionChange) {
|
|
const socialCard = await db.socialCard.findUnique({
|
|
where: { projectId },
|
|
})
|
|
if (socialCard) {
|
|
return db.socialCard.update({
|
|
data: { outOfDate: true },
|
|
where: { id: socialCard.id },
|
|
})
|
|
}
|
|
}
|
|
}
|
|
requireAuth()
|
|
const originalProject = await requireProjectOwnership({ projectId: id })
|
|
console.log('yooooo', originalProject)
|
|
if (input.title) {
|
|
input.title = enforceAlphaNumeric(input.title)
|
|
}
|
|
const socialCardPromise = checkSocialCardValidity(id, input, originalProject)
|
|
const imageToDestroy =
|
|
originalProject.mainImage !== input.mainImage &&
|
|
input.mainImage &&
|
|
originalProject.mainImage
|
|
const update = await db.project.update({
|
|
data: foreignKeyReplacement(input),
|
|
where: { id },
|
|
})
|
|
if (imageToDestroy) {
|
|
console.log(
|
|
`image destroyed, publicId: ${imageToDestroy}, projectId: ${id}, replacing image is ${input.mainImage}`
|
|
)
|
|
// destroy after the db has been updated
|
|
await destroyImage({ publicId: imageToDestroy })
|
|
}
|
|
await socialCardPromise
|
|
return update
|
|
}
|
|
|
|
export const updateProjectImages = async ({
|
|
id,
|
|
mainImage64,
|
|
socialCard64,
|
|
}: {
|
|
id: string
|
|
mainImage64?: string
|
|
socialCard64?: string
|
|
}): Promise<ProjectType> => {
|
|
requireAuth()
|
|
const project = await requireProjectOwnership({ projectId: id })
|
|
const replaceSocialCard = async () => {
|
|
if (!socialCard64) {
|
|
return
|
|
}
|
|
let publicId = ''
|
|
let socialCardId = ''
|
|
try {
|
|
;({ id: socialCardId, url: publicId } = await db.socialCard.findUnique({
|
|
where: { projectId: id },
|
|
}))
|
|
} catch (e) {
|
|
const { userName } = await db.user.findUnique({
|
|
where: { id: project.userId },
|
|
})
|
|
publicId = makeSocialPublicIdServer(userName, project.title)
|
|
}
|
|
const imagePromise = uploadImage({
|
|
image64: socialCard64,
|
|
uploadPreset: 'CadHub_project_images',
|
|
publicId,
|
|
invalidate: true,
|
|
})
|
|
const saveOrUpdateSocialCard = () => {
|
|
const data = {
|
|
outOfDate: false,
|
|
url: publicId,
|
|
}
|
|
if (socialCardId) {
|
|
return db.socialCard.update({
|
|
data,
|
|
where: { projectId: id },
|
|
})
|
|
}
|
|
return db.socialCard.create({
|
|
data: {
|
|
...data,
|
|
project: {
|
|
connect: {
|
|
id: id,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
const socialCardUpdatePromise = saveOrUpdateSocialCard()
|
|
const [socialCard] = await Promise.all([
|
|
socialCardUpdatePromise,
|
|
imagePromise,
|
|
])
|
|
return socialCard
|
|
}
|
|
|
|
const updateMainImage = async (): Promise<ProjectType> => {
|
|
if (!mainImage64) {
|
|
return project
|
|
}
|
|
const { public_id: mainImage } = await uploadImage({
|
|
image64: mainImage64,
|
|
uploadPreset: 'CadHub_project_images',
|
|
invalidate: true,
|
|
})
|
|
const projectPromise = db.project.update({
|
|
data: {
|
|
mainImage,
|
|
},
|
|
where: { id },
|
|
})
|
|
let imageDestroyPromise = new Promise((r) => r(null))
|
|
if (project.mainImage) {
|
|
console.log(
|
|
`image destroyed, publicId: ${project.mainImage}, projectId: ${id}, replacing image is ${mainImage}`
|
|
)
|
|
// destroy after the db has been updated
|
|
imageDestroyPromise = destroyImage({ publicId: project.mainImage })
|
|
}
|
|
const [updatedProject] = await Promise.all([
|
|
projectPromise,
|
|
imageDestroyPromise,
|
|
])
|
|
return updatedProject
|
|
}
|
|
|
|
const [updatedProject] = await Promise.all([
|
|
updateMainImage(),
|
|
replaceSocialCard(),
|
|
])
|
|
|
|
return updatedProject
|
|
}
|
|
|
|
export const deleteProject = async ({ id }: Prisma.ProjectWhereUniqueInput) => {
|
|
requireAuth()
|
|
await requireOwnership({ projectId: id })
|
|
return db.project.update({
|
|
data: {
|
|
deleted: true,
|
|
},
|
|
where: { id },
|
|
})
|
|
}
|
|
|
|
export const Project = {
|
|
forkedFrom: (_obj, { root }) =>
|
|
root.forkedFromId &&
|
|
db.project.findUnique({ where: { id: root.forkedFromId } }),
|
|
childForks: (_obj, { root }) =>
|
|
db.project.findMany({ where: { forkedFromId: root.id } }),
|
|
user: (_obj, { root }: ResolverArgs<ReturnType<typeof project>>) =>
|
|
db.project.findUnique({ where: { id: root.id } }).user(),
|
|
socialCard: (_obj, { root }: ResolverArgs<ReturnType<typeof project>>) =>
|
|
db.project.findUnique({ where: { id: root.id } }).socialCard(),
|
|
Comment: (_obj, { root }: ResolverArgs<ReturnType<typeof project>>) =>
|
|
db.project
|
|
.findUnique({ where: { id: root.id } })
|
|
.Comment({ orderBy: { createdAt: 'desc' } }),
|
|
Reaction: (_obj, { root }: ResolverArgs<ReturnType<typeof project>>) =>
|
|
db.project
|
|
.findUnique({ where: { id: root.id } })
|
|
.Reaction({ where: { userId: _obj.userId } }),
|
|
}
|