feat: add image management for stories and user avatar

This commit is contained in:
Dolu
2022-09-09 17:42:43 +02:00
parent 35ccec37b2
commit acdf617fb0
14 changed files with 256 additions and 54 deletions

View File

@@ -88,7 +88,6 @@ export interface NexusGenScalars {
export interface NexusGenObjects {
Author: { // root type
avatar: string; // String!
id: number; // Int!
join_date: NexusGenScalars['Date']; // Date!
lightning_address?: string | null; // String

View File

@@ -5,7 +5,7 @@ const {
nonNull,
} = require('nexus');
const { prisma } = require('../../../prisma');
const resolveImgObjectToUrl = require('../../../utils/resolveImageUrl');
const { resolveImgObjectToUrl } = require('../../../utils/resolveImageUrl');
const Category = objectType({
@@ -15,6 +15,7 @@ const Category = objectType({
t.nonNull.string('title');
t.string('cover_image', {
async resolve(parent) {
if (!parent.cover_image_id) return null
const imgObject = await prisma.hostedImage.findUnique({
where: {
id: parent.cover_image_id

View File

@@ -6,7 +6,7 @@ const {
nonNull,
} = require('nexus');
const { prisma } = require('../../../prisma');
const resolveImgObjectToUrl = require('../../../utils/resolveImageUrl');
const { resolveImgObjectToUrl } = require('../../../utils/resolveImageUrl');
@@ -18,6 +18,7 @@ const Hackathon = objectType({
t.nonNull.string('description');
t.nonNull.string('cover_image', {
async resolve(parent) {
if (!parent.cover_image_id) return null
const imgObject = await prisma.hostedImage.findUnique({
where: {
id: parent.cover_image_id

View File

@@ -15,8 +15,9 @@ const { prisma } = require('../../../prisma');
const { getUserByPubKey } = require('../../../auth/utils/helperFuncs');
const { ApolloError } = require('apollo-server-lambda');
const { marked } = require('marked');
const resolveImgObjectToUrl = require('../../../utils/resolveImageUrl');
const { resolveImgObjectToUrl } = require('../../../utils/resolveImageUrl');
const { ImageInput } = require('./misc');
const { deleteImage } = require('../../../services/imageUpload.service');
const POST_TYPE = enumType({
@@ -39,7 +40,17 @@ const Author = objectType({
definition(t) {
t.nonNull.int('id');
t.nonNull.string('name');
t.nonNull.string('avatar');
t.nonNull.string('avatar', {
async resolve(parent) {
const imgObject = await prisma.hostedImage.findUnique({
where: {
id: parent.avatar_id
}
});
return resolveImgObjectToUrl(imgObject);
}
});
t.nonNull.date('join_date');
t.string('lightning_address');
@@ -75,6 +86,7 @@ const Story = objectType({
});
t.string('cover_image', {
async resolve(parent) {
if (!parent.cover_image_id) return null
const imgObject = await prisma.hostedImage.findUnique({
where: {
id: parent.cover_image_id
@@ -153,6 +165,7 @@ const Bounty = objectType({
});
t.string('cover_image', {
async resolve(parent) {
if (!parent.cover_image_id) return null
const imgObject = await prisma.hostedImage.findUnique({
where: {
id: parent.cover_image_id
@@ -366,6 +379,64 @@ const getPostById = extendType({
}
})
const addCoverImage = async (providerImageId) => {
const newCoverImage = await prisma.hostedImage.findFirst({
where: {
provider_image_id: providerImageId
}
})
if (!newCoverImage) throw new ApolloError("New cover image not found")
await prisma.hostedImage.update({
where: {
id: newCoverImage.id
},
data: {
is_used: true
}
})
return newCoverImage
}
const getHostedImageIdsFromBody = async (body, oldBodyImagesIds = null) => {
let bodyImageIds = []
const regex = /(?:!\[(.*?)\]\((.*?)\))/g
let match;
while((match = regex.exec(body))) {
const [,,value] = match
// Useful for old external images in case of duplicates. We need to be sure we are targeting an image from the good story.
const where = oldBodyImagesIds ? {
AND: [
{ url: value },
{ id: { in: oldBodyImagesIds } }
]
} :
{
url: value,
}
const hostedImage = await prisma.hostedImage.findFirst({
where
})
if (hostedImage) {
bodyImageIds.push(hostedImage.id)
await prisma.hostedImage.update({
where: {
id: hostedImage.id
},
data: {
is_used: true
}
})
}
}
return bodyImageIds
}
const createStory = extendType({
type: 'Mutation',
definition(t) {
@@ -382,20 +453,64 @@ const createStory = extendType({
let was_published = false;
// TODO: validate post data
let coverImage = null
let bodyImageIds = []
// Edit story
if (id) {
const oldPost = await prisma.story.findFirst({
where: { id },
select: {
user_id: true,
is_published: true
is_published: true,
cover_image_id: true,
body_image_ids: true
}
})
was_published = oldPost.is_published;
if (user.id !== oldPost.user_id)
throw new ApolloError("Not post author")
}
// TODO: validate post data
if (user.id !== oldPost.user_id) throw new ApolloError("Not post author")
// Body images
bodyImageIds = await getHostedImageIdsFromBody(body, oldPost.body_image_ids)
// Old cover image is found
if (oldPost.cover_image_id) {
const oldCoverImage = await prisma.hostedImage.findFirst({
where : {
id: oldPost.cover_image_id
}
})
// New cover image
if (cover_image?.id && cover_image.id !== oldCoverImage?.provider_image_id) {
await deleteImage(oldCoverImage.id)
coverImage = await addCoverImage(cover_image.id)
} else {
coverImage = oldCoverImage
}
} else {
// No old image found and new cover image
if (cover_image?.id) {
coverImage = await addCoverImage(cover_image.id)
}
}
// Remove unused body images
const unusedImagesIds = oldPost.body_image_ids.filter(x => !bodyImageIds.includes(x));
unusedImagesIds.map(async i => await deleteImage(i))
} else {
// Body images
bodyImageIds = await getHostedImageIdsFromBody(body)
// New story and new cover image
if (cover_image?.id) {
coverImage = await addCoverImage(cover_image.id)
}
}
// Preprocess & insert
const htmlBody = marked.parse(body);
@@ -408,12 +523,14 @@ const createStory = extendType({
;
// ----------------
// Check the uploaded cover image & the images in the body,
// remove the old one from the hosting service, then replace it with these ones
// ----------------
const coverImageRel = coverImage ? {
cover_image_rel: {
connect:
{
id: coverImage ? coverImage.id : null
}
}
} : {}
if (id) {
await prisma.story.update({
@@ -430,7 +547,7 @@ const createStory = extendType({
data: {
title,
body,
cover_image: cover_image.url,
cover_image: '',
excerpt,
is_published: was_published || is_published,
tags: {
@@ -447,16 +564,17 @@ const createStory = extendType({
}
})
},
body_image_ids: bodyImageIds,
...coverImageRel
}
})
}
return prisma.story.create({
return await prisma.story.create({
data: {
title,
body,
cover_image: cover_image.url,
cover_image: '',
excerpt,
is_published,
tags: {
@@ -477,7 +595,9 @@ const createStory = extendType({
connect: {
id: user.id,
}
}
},
body_image_ids: bodyImageIds,
...coverImageRel
}
})
}
@@ -502,17 +622,39 @@ const deleteStory = extendType({
const oldPost = await prisma.story.findFirst({
where: { id },
select: {
user_id: true
user_id: true,
body_image_ids: true,
cover_image_id: true
}
})
if (user.id !== oldPost.user_id)
throw new ApolloError("Not post author")
return prisma.story.delete({
const deletedPost = await prisma.story.delete({
where: {
id
}
})
const coverImage = await prisma.hostedImage.findMany({
where: {
OR: [
{ id: oldPost.cover_image_id },
{
id: {
in: oldPost.body_image_ids
}
}
]
},
select: {
id: true,
provider_image_id: true
}
})
coverImage.map(async i => await deleteImage(i.id))
return deletedPost
}
})
},

View File

@@ -6,7 +6,7 @@ const {
nonNull,
} = require('nexus')
const { prisma } = require('../../../prisma');
const resolveImgObjectToUrl = require('../../../utils/resolveImageUrl');
const { resolveImgObjectToUrl } = require('../../../utils/resolveImageUrl');
const { paginationArgs, getLnurlDetails, lightningAddressToLnurl } = require('./helpers');
const { MakerRole } = require('./users');
@@ -20,6 +20,7 @@ const Project = objectType({
t.nonNull.string('description');
t.nonNull.string('cover_image', {
async resolve(parent) {
if (!parent.cover_image_id) return null
const imgObject = await prisma.hostedImage.findUnique({
where: {
id: parent.cover_image_id
@@ -31,6 +32,7 @@ const Project = objectType({
});
t.nonNull.string('thumbnail_image', {
async resolve(parent) {
if (!parent.thumbnail_image_id) return null
const imgObject = await prisma.hostedImage.findUnique({
where: {
id: parent.thumbnail_image_id
@@ -42,6 +44,7 @@ const Project = objectType({
});
t.nonNull.list.nonNull.string('screenshots', {
async resolve(parent) {
if (!parent.screenshots_ids) return null
const imgObject = await prisma.hostedImage.findMany({
where: {
id: { in: parent.screenshots_ids }

View File

@@ -6,6 +6,7 @@ const {
nonNull,
} = require('nexus');
const { prisma } = require('../../../prisma');
const { resolveImgObjectToUrl } = require('../../../utils/resolveImageUrl');
@@ -18,6 +19,7 @@ const Tournament = objectType({
t.nonNull.string('thumbnail_image');
t.nonNull.string('cover_image', {
async resolve(parent) {
if (!parent.cover_image_id) return null
const imgObject = await prisma.hostedImage.findUnique({
where: {
id: parent.cover_image_id

View File

@@ -5,7 +5,7 @@ const { getUserByPubKey } = require("../../../auth/utils/helperFuncs");
const { removeNulls } = require("./helpers");
const { ImageInput } = require('./misc');
const { Tournament } = require('./tournaments');
const resolveImgObjectToUrl = require('../../../utils/resolveImageUrl');
const { resolveImgObjectToUrl } = require('../../../utils/resolveImageUrl');
const { deleteImage } = require('../../../services/imageUpload.service');
@@ -18,6 +18,7 @@ const BaseUser = interfaceType({
t.nonNull.string('name');
t.nonNull.string('avatar', {
async resolve(parent) {
if (!parent.avatar_id) return null
const imgObject = await prisma.hostedImage.findUnique({
where: {
id: parent.avatar_id
@@ -301,15 +302,6 @@ const updateProfileDetails = extendType({
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
@@ -319,7 +311,7 @@ const updateProfileDetails = extendType({
}
});
deleteImage(user.avatar_id)
await deleteImage(user.avatar_id)
}
}