mirror of
https://github.com/aljazceru/landscape-template.git
synced 2026-01-31 04:04:27 +01:00
feat: connect user avatar upload with the HostedImage table
This commit is contained in:
@@ -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: '',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user