feat: connect user avatar upload with the HostedImage table

This commit is contained in:
Dolu
2022-09-07 15:07:18 +02:00
parent 56a9a70c70
commit 35ccec37b2
5 changed files with 125 additions and 12 deletions

View File

@@ -6,6 +6,7 @@ const { removeNulls } = require("./helpers");
const { ImageInput } = require('./misc');
const { Tournament } = require('./tournaments');
const resolveImgObjectToUrl = require('../../../utils/resolveImageUrl');
const { deleteImage } = require('../../../services/imageUpload.service');
@@ -288,6 +289,39 @@ const updateProfileDetails = extendType({
// Check if the user uploaded a new image, and if so,
// remove the old one from the hosting service, then replace it with this one
// ----------------
let avatarId = user.avatar_id;
if (args.data.avatar.id) {
const newAvatarProviderId = args.data.avatar.id;
const newAvatar = await prisma.hostedImage.findFirst({
where: {
provider_image_id: newAvatarProviderId
}
})
if (newAvatar && newAvatar.id !== user.avatar_id) {
avatarId = newAvatar.id;
// Set is_used to false in case of deleteImage() fail. The scheduled job will try to delete the HostedImage row
await prisma.hostedImage.update({
where: {
id: user.avatar_id
},
data: {
is_used: false
}
});
await prisma.hostedImage.update({
where: {
id: newAvatar.id
},
data: {
is_used: true
}
});
deleteImage(user.avatar_id)
}
}
// Preprocess & insert
return prisma.user.update({
@@ -296,7 +330,11 @@ const updateProfileDetails = extendType({
},
data: removeNulls({
...args.data,
avatar: args.data.avatar?.url,
avatar_id: avatarId,
//hack to remove avatar from args.data
// can be removed later with a schema data validator
avatar: '',
})
})
}

View File

@@ -8,8 +8,6 @@ const { prisma } = require('../../prisma')
const postUploadImageUrl = async (req, res) => {
// return res.status(404).send("This api is in progress");
const userPubKey = await extractKeyFromCookie(req.headers.cookie ?? req.headers.Cookie)
const user = await getUserByPubKey(userPubKey)
@@ -23,10 +21,15 @@ const postUploadImageUrl = async (req, res) => {
const uploadUrl = await getDirectUploadUrl()
const hostedImage = await prisma.hostedImage.create({
data: { filename },
data: {
filename,
url: uploadUrl.uploadURL,
provider_image_id: uploadUrl.id,
provider: uploadUrl.provider
},
})
return res.status(200).json({ id: hostedImage.id, uploadUrl: uploadUrl.uploadUrl })
return res.status(200).json({ id: hostedImage.id, uploadURL: uploadUrl.uploadURL })
} catch (error) {
res.status(500).send('Unexpected error happened, please try again')
}

View File

@@ -1,11 +1,21 @@
const { CONSTS } = require('../utils')
const axios = require('axios')
const FormData = require('form-data')
const { prisma } = require('../prisma')
const BASE_URL = 'https://api.cloudflare.com/client/v4'
const operationUrls = {
'image.uploadUrl': `${BASE_URL}/accounts/${CONSTS.CLOUDFLARE_IMAGE_ACCOUNT_ID}/images/v2/direct_upload`,
'image.delete': `${BASE_URL}/accounts/${CONSTS.CLOUDFLARE_IMAGE_ACCOUNT_ID}/images/v1/`,
}
function getAxiosConfig() {
return {
headers: {
Authorization: `Bearer ${CONSTS.CLOUDFLARE_IMAGE_API_KEY}`,
},
}
}
async function getDirectUploadUrl() {
@@ -27,9 +37,38 @@ async function getDirectUploadUrl() {
throw new Error(result.data, { cause: result.data.errors })
}
return result.data.result
const data = result.data.result
return { id: data.id, uploadURL: data.uploadURL, provider: 'cloudflare' }
}
async function deleteImage(hostedImageId) {
if (!hostedImageId) throw new Error("argument 'hostedImageId' must be provider")
const hostedImage = await prisma.hostedImage.findFirst({
where: {
id: hostedImageId,
},
})
if (!hostedImage) throw new Error(`No HostedImage row found for HostedImage.id=${hostedImageId}`)
if (hostedImage.provider_image_id && hostedImage.provider_image_id === '') throw new Error(`Field 'provider_image_id' for HostedImage.id=${hostedImageId} must not be empty. Current value '${hostedImage.provider_image_id}'`)
const url = operationUrls['image.delete'] + hostedImage.provider_image_id
const result = await axios.delete(url, getAxiosConfig())
if (!result.data.success) {
throw new Error(result.data, { cause: result.data.errors })
}
await prisma.hostedImage.delete({
where: {
id: hostedImageId,
},
})
}
module.exports = {
getDirectUploadUrl,
deleteImage,
}

View File

@@ -3,6 +3,7 @@ const JWT_SECRET = process.env.JWT_SECRET
const LNURL_AUTH_HOST = process.env.LNURL_AUTH_HOST
const CLOUDFLARE_IMAGE_ACCOUNT_ID = process.env.CLOUDFLARE_IMAGE_ACCOUNT_ID
const CLOUDFLARE_IMAGE_API_KEY = process.env.CLOUDFLARE_IMAGE_API_KEY
const CLOUDFLARE_IMAGE_ACCOUNT_HASH = process.env.CLOUDFLARE_IMAGE_ACCOUNT_HASH
const CONSTS = {
JWT_SECRET,
@@ -10,6 +11,7 @@ const CONSTS = {
LNURL_AUTH_HOST,
CLOUDFLARE_IMAGE_ACCOUNT_ID,
CLOUDFLARE_IMAGE_API_KEY,
CLOUDFLARE_IMAGE_ACCOUNT_HASH
}
module.exports = CONSTS

View File

@@ -1,10 +1,41 @@
function resolveImgObjectToUrl(imgObject) {
if(imgObject && imgObject.provider === 'external'){
return imgObject.url;
const { CLOUDFLARE_IMAGE_ACCOUNT_HASH } = require('./consts')
const PROVIDERS = [
{
name: 'cloudflare',
prefixUrl: `https://imagedelivery.net/${CLOUDFLARE_IMAGE_ACCOUNT_HASH}/`,
variants: [
{
default: true,
name: 'public',
},
],
},
]
/**
* resolveImgObjectToUrl
* @param {object} imgObject
* @param {string} variant - List to be defined. DEFAULT TO 'public'
* @returns {string} image url
*/
function resolveImgObjectToUrl(imgObject, variant = null) {
if (!imgObject) throw new Error('Image not found')
if (imgObject.provider === 'external') {
return imgObject.url
}
else {
return "TODO";
const provider = PROVIDERS.find((p) => p.name === imgObject.provider)
if (provider) {
if (provider && provider.name === 'cloudflare') {
const variantName = variant ?? provider.variants.find((v) => v.default).name
return provider.prefixUrl + imgObject.provider_image_id + '/' + variantName
}
}
throw new Error('Hosting images provider not supported')
}
module.exports = resolveImgObjectToUrl;
module.exports = resolveImgObjectToUrl