Get image upload to cloudinary with the same public id

This means we can put a consistent url in the head for the card image
This commit is contained in:
Kurt Hutten
2021-08-14 15:19:48 +10:00
parent 50e9ac61f8
commit 32155ba98c
17 changed files with 425 additions and 77 deletions

View File

@@ -0,0 +1,72 @@
import type { APIGatewayEvent } from 'aws-lambda'
import { logger } from 'src/lib/logger'
import { v2 as cloudinary, UploadApiResponse } from 'cloudinary'
// import { requireOwnership } from 'src/lib/owner'
// import { requireAuth } from 'src/lib/auth'
cloudinary.config({
cloud_name: 'irevdev',
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
})
/**
* The handler function is your code that processes http request events.
* You can use return and throw to send a response or error, respectively.
*
* Important: When deployed, a custom serverless function is an open API endpoint and
* is your responsibility to secure appropriately.
*
* @see {@link https://redwoodjs.com/docs/serverless-functions#security-considerations|Serverless Function Considerations}
* in the RedwoodJS documentation for more information.
*
* @typedef { import('aws-lambda').APIGatewayEvent } APIGatewayEvent
* @typedef { import('aws-lambda').Context } Context
* @param { APIGatewayEvent } event - an object which contains information from the invoker.
* @param { Context } context - contains information about the invocation,
* function, and execution environment.
*/
export const handler = async (event: APIGatewayEvent, _context) => {
logger.info('Invoked image-upload function')
// requireAuth()
const {
image64,
upload_preset,
public_id,
invalidate,
projectId,
}: {
image64: string
upload_preset: string
public_id: string
invalidate: boolean
projectId: string
} = JSON.parse(event.body)
// await requireOwnership({projectId})
const uploadResult: UploadApiResponse = await new Promise(
(resolve, reject) => {
cloudinary.uploader.upload(
image64,
{ upload_preset, public_id, invalidate },
(error, result) => {
if (error) {
reject(error)
return
}
resolve(result)
}
)
}
)
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
publicId: uploadResult.public_id,
}),
}
}

View File

@@ -11,6 +11,7 @@ export const schema = gql`
userId: String!
deleted: Boolean!
cadPackage: CadPackage!
socialCard: SocialCard
Comment: [Comment]!
Reaction(userId: String): [ProjectReaction]!
}

View File

@@ -0,0 +1,35 @@
export const schema = gql`
type SocialCard {
id: String!
projectId: String!
project: Project!
createdAt: DateTime!
updatedAt: DateTime!
url: String
outOfDate: Boolean!
}
type Query {
socialCards: [SocialCard!]!
socialCard(id: String!): SocialCard
}
input CreateSocialCardInput {
projectId: String!
url: String
outOfDate: Boolean!
}
input UpdateSocialCardInput {
projectId: String
url: String
outOfDate: Boolean
}
type Mutation {
createSocialCard(input: CreateSocialCardInput!): SocialCard!
updateSocialCard(id: String!, input: UpdateSocialCardInput!): SocialCard!
deleteSocialCard(id: String!): SocialCard!
updateSocialCardByProjectId(projectId: String!, url: String!): SocialCard!
}
`

View File

@@ -5,10 +5,16 @@ export const requireOwnership = async ({
userId,
userName,
projectId,
}: { userId?: string; userName?: string; projectId?: string } = {}) => {
sub,
}: {
userId?: string
userName?: string
projectId?: string
sub?: string
} = {}) => {
// IMPORTANT, don't forget to await this function, as it will only block
// unwanted db actions if it has time to look up resources in the db.
if (!context.currentUser) {
if (!(context?.currentUser || sub)) {
throw new AuthenticationError("You don't have permission to do that.")
}
if (!userId && !userName && !projectId) {
@@ -22,7 +28,7 @@ export const requireOwnership = async ({
return
}
const netlifyUserId = context.currentUser?.sub
const netlifyUserId = context?.currentUser?.sub || sub
if (userId && userId !== netlifyUserId) {
throw new ForbiddenError("You don't own this resource.")
}

View File

@@ -130,6 +130,8 @@ export const deleteProject = async ({ id }: Prisma.ProjectWhereUniqueInput) => {
export const Project = {
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 } })

View File

@@ -0,0 +1,84 @@
import type { Prisma } from '@prisma/client'
import type { ResolverArgs, BeforeResolverSpecType } from '@redwoodjs/api'
import { db } from 'src/lib/db'
import { requireAuth } from 'src/lib/auth'
// Used when the environment variable REDWOOD_SECURE_SERVICES=1
export const beforeResolver = (rules: BeforeResolverSpecType) => {
rules.add(requireAuth)
}
export const socialCards = () => {
return db.socialCard.findMany()
}
export const socialCard = ({ id }: Prisma.SocialCardWhereUniqueInput) => {
return db.socialCard.findUnique({
where: { id },
})
}
interface CreateSocialCardArgs {
input: Prisma.SocialCardCreateInput
}
export const createSocialCard = ({ input }: CreateSocialCardArgs) => {
return db.socialCard.create({
data: input,
})
}
interface UpdateSocialCardArgs extends Prisma.SocialCardWhereUniqueInput {
input: Prisma.SocialCardUpdateInput
}
export const updateSocialCard = ({ id, input }: UpdateSocialCardArgs) => {
return db.socialCard.update({
data: input,
where: { id },
})
}
export const updateSocialCardByProjectId = async ({
projectId,
url,
}: {
url: string
projectId: string
}) => {
let id: string
try {
const socialCard = await db.project
.findUnique({ where: { id: projectId } })
.socialCard()
id = socialCard.id
} catch (e) {
return db.socialCard.create({
data: {
url,
project: {
connect: {
id: projectId,
},
},
},
})
}
return db.socialCard.update({
data: { url },
where: { id },
})
}
export const deleteSocialCard = ({ id }: Prisma.SocialCardWhereUniqueInput) => {
return db.socialCard.delete({
where: { id },
})
}
export const SocialCard = {
project: (_obj, { root }: ResolverArgs<ReturnType<typeof socialCard>>) =>
db.socialCard.findUnique({ where: { id: root.id } }).project(),
}