mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
refactor image services
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"clear-db": "npx ts-node ./src/prisma/seed/clear/index.ts",
|
"clear-db": "npx ts-node ./src/prisma/seed/clear/index.ts",
|
||||||
"format": "npx prettier . --write",
|
"format": "npx prettier . --write; npx prisma format;",
|
||||||
"format-watch": "npx onchange \"**/*\" -- prettier --write --ignore-unknown {{changed}}",
|
"format-watch": "npx onchange \"**/*\" -- prettier --write --ignore-unknown {{changed}}",
|
||||||
"seed": "npx --max-old-space-size=4096 ts-node ./src/prisma/seed/index.ts"
|
"seed": "npx --max-old-space-size=4096 ts-node ./src/prisma/seed/index.ts"
|
||||||
},
|
},
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"@mapbox/search-js-core": "^1.0.0-beta.17",
|
"@mapbox/search-js-core": "^1.0.0-beta.17",
|
||||||
"@mapbox/search-js-react": "^1.0.0-beta.17",
|
"@mapbox/search-js-react": "^1.0.0-beta.17",
|
||||||
"@next/bundle-analyzer": "^14.0.3",
|
"@next/bundle-analyzer": "^14.0.3",
|
||||||
"@prisma/client": "^5.6.0",
|
"@prisma/client": "^5.7.0",
|
||||||
"@react-email/components": "^0.0.11",
|
"@react-email/components": "^0.0.11",
|
||||||
"@react-email/render": "^0.0.9",
|
"@react-email/render": "^0.0.9",
|
||||||
"@react-email/tailwind": "^0.0.12",
|
"@react-email/tailwind": "^0.0.12",
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
"prettier-plugin-jsdoc": "^1.0.2",
|
"prettier-plugin-jsdoc": "^1.0.2",
|
||||||
"prettier-plugin-tailwindcss": "^0.5.7",
|
"prettier-plugin-tailwindcss": "^0.5.7",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"prisma": "^5.6.0",
|
"prisma": "^5.7.0",
|
||||||
"tailwindcss-animate": "^1.0.6",
|
"tailwindcss-animate": "^1.0.6",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
|||||||
11
src/config/cloudinary/helpers/deleteImage.ts
Normal file
11
src/config/cloudinary/helpers/deleteImage.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { cloudinary } from '..';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an image from Cloudinary.
|
||||||
|
*
|
||||||
|
* @param path - The cloudinary path of the image to be deleted.
|
||||||
|
* @returns A promise that resolves when the image is successfully deleted.
|
||||||
|
*/
|
||||||
|
const deleteImage = (path: string) => cloudinary.uploader.destroy(path);
|
||||||
|
|
||||||
|
export default deleteImage;
|
||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,
|
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,
|
||||||
CLOUDINARY_KEY,
|
CLOUDINARY_KEY,
|
||||||
CLOUDINARY_SECRET,
|
CLOUDINARY_SECRET,
|
||||||
|
NODE_ENV,
|
||||||
} from '../env';
|
} from '../env';
|
||||||
import CloudinaryStorage from './CloudinaryStorage';
|
import CloudinaryStorage from './CloudinaryStorage';
|
||||||
|
|
||||||
@@ -14,6 +15,9 @@ cloudinary.config({
|
|||||||
});
|
});
|
||||||
|
|
||||||
/** Cloudinary storage instance. */
|
/** Cloudinary storage instance. */
|
||||||
const storage = new CloudinaryStorage({ cloudinary, params: { folder: 'biergarten' } });
|
const storage = new CloudinaryStorage({
|
||||||
|
cloudinary,
|
||||||
|
params: { folder: NODE_ENV === 'production' ? 'biergarten' : 'biergarten-dev' },
|
||||||
|
});
|
||||||
|
|
||||||
export { cloudinary, storage };
|
export { cloudinary, storage };
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import ServerError from '@/config/util/ServerError';
|
import ServerError from '@/config/util/ServerError';
|
||||||
import addBeerImageToDB from '@/services/images/beer-image/addBeerImageToDB';
|
import {
|
||||||
|
addBeerImagesToDB,
|
||||||
|
deleteBeerImageFromDBAndStorage,
|
||||||
|
} from '@/services/images/beer-image';
|
||||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { UploadImagesRequest } from '../types';
|
import { DeleteImageRequest, UploadImagesRequest } from '../types';
|
||||||
|
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
export const processBeerImageData = async (
|
export const processBeerImageData = async (
|
||||||
@@ -16,11 +19,10 @@ export const processBeerImageData = async (
|
|||||||
throw new ServerError('No images uploaded', 400);
|
throw new ServerError('No images uploaded', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
const beerImages = await addBeerImageToDB({
|
const beerImages = await addBeerImagesToDB({
|
||||||
alt: body.alt,
|
|
||||||
caption: body.caption,
|
|
||||||
beerPostId: req.query.id,
|
beerPostId: req.query.id,
|
||||||
userId: user!.id,
|
userId: user!.id,
|
||||||
|
body,
|
||||||
files,
|
files,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -32,3 +34,18 @@ export const processBeerImageData = async (
|
|||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const deleteBeerImageData = async (
|
||||||
|
req: DeleteImageRequest,
|
||||||
|
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||||
|
) => {
|
||||||
|
const { id } = req.query;
|
||||||
|
|
||||||
|
await deleteBeerImageFromDBAndStorage({ beerImageId: id });
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
message: `Successfully deleted image with id ${id}`,
|
||||||
|
statusCode: 200,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import ServerError from '@/config/util/ServerError';
|
import ServerError from '@/config/util/ServerError';
|
||||||
import addBreweryImageToDB from '@/services/images/brewery-image/addBreweryImageToDB';
|
|
||||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { addBreweryImagesToDB } from '@/services/images/brewery-image';
|
||||||
import { UploadImagesRequest } from '../types';
|
import { UploadImagesRequest } from '../types';
|
||||||
|
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
@@ -16,11 +17,10 @@ export const processBreweryImageData = async (
|
|||||||
throw new ServerError('No images uploaded', 400);
|
throw new ServerError('No images uploaded', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
const breweryImages = await addBreweryImageToDB({
|
const breweryImages = await addBreweryImagesToDB({
|
||||||
alt: body.alt,
|
|
||||||
caption: body.caption,
|
|
||||||
breweryPostId: req.query.id,
|
breweryPostId: req.query.id,
|
||||||
userId: user!.id,
|
userId: user!.id,
|
||||||
|
body,
|
||||||
files,
|
files,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -7,3 +7,7 @@ export interface UploadImagesRequest extends UserExtendedNextApiRequest {
|
|||||||
query: { id: string };
|
query: { id: string };
|
||||||
body: z.infer<typeof ImageMetadataValidationSchema>;
|
body: z.infer<typeof ImageMetadataValidationSchema>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DeleteImageRequest extends UserExtendedNextApiRequest {
|
||||||
|
query: { id: string };
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import ServerError from '@/config/util/ServerError';
|
|||||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||||
import { NextApiResponse, NextApiRequest } from 'next';
|
import { NextApiResponse, NextApiRequest } from 'next';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { LikeRequest } from '../types';
|
|
||||||
import createBeerPostLike from '@/services/likes/beer-post-like/createBeerPostLike';
|
import createBeerPostLike from '@/services/likes/beer-post-like/createBeerPostLike';
|
||||||
import findBeerPostLikeById from '@/services/likes/beer-post-like/findBeerPostLikeById';
|
import findBeerPostLikeById from '@/services/likes/beer-post-like/findBeerPostLikeById';
|
||||||
import getBeerPostLikeCountByBeerPostId from '@/services/likes/beer-post-like/getBeerPostLikeCount';
|
import getBeerPostLikeCountByBeerPostId from '@/services/likes/beer-post-like/getBeerPostLikeCount';
|
||||||
import removeBeerPostLikeById from '@/services/likes/beer-post-like/removeBeerPostLikeById';
|
import removeBeerPostLikeById from '@/services/likes/beer-post-like/removeBeerPostLikeById';
|
||||||
import { getBeerPostById } from '@/services/posts/beer-post';
|
import { getBeerPostById } from '@/services/posts/beer-post';
|
||||||
|
import { LikeRequest } from '../types';
|
||||||
|
|
||||||
export const sendBeerPostLikeRequest = async (
|
export const sendBeerPostLikeRequest = async (
|
||||||
req: LikeRequest,
|
req: LikeRequest,
|
||||||
@@ -20,7 +20,7 @@ export const sendBeerPostLikeRequest = async (
|
|||||||
|
|
||||||
const beer = await getBeerPostById({ beerPostId: id });
|
const beer = await getBeerPostById({ beerPostId: id });
|
||||||
if (!beer) {
|
if (!beer) {
|
||||||
throw new ServerError('Could not find a beer post with that id', 404);
|
throw new ServerError('Could not find a beer post with that id.', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
const alreadyLiked = await findBeerPostLikeById({
|
const alreadyLiked = await findBeerPostLikeById({
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import getAllBeerStyles from '@/services/posts/beer-style-post/getAllBeerStyles'
|
|||||||
|
|
||||||
import ServerError from '@/config/util/ServerError';
|
import ServerError from '@/config/util/ServerError';
|
||||||
|
|
||||||
|
import { getBeerPostsByBeerStyleIdService } from '@/services/posts/beer-post';
|
||||||
import { CreateBeerStyleRequest, GetBeerStyleByIdRequest } from './types';
|
import { CreateBeerStyleRequest, GetBeerStyleByIdRequest } from './types';
|
||||||
import { GetAllPostsByConnectedPostId, GetAllPostsRequest } from '../types';
|
import { GetAllPostsByConnectedPostId, GetAllPostsRequest } from '../types';
|
||||||
import { getBeerPostsByBeerStyleIdService } from '@/services/posts/beer-post';
|
|
||||||
|
|
||||||
export const getBeerStyle = async (
|
export const getBeerStyle = async (
|
||||||
req: GetBeerStyleByIdRequest,
|
req: GetBeerStyleByIdRequest,
|
||||||
|
|||||||
7
src/prisma/seed/clear/clearCloudinaryStorage.ts
Normal file
7
src/prisma/seed/clear/clearCloudinaryStorage.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { cloudinary } from '../../../config/cloudinary';
|
||||||
|
|
||||||
|
const clearCloudinaryStorage = async () => {
|
||||||
|
await cloudinary.api.delete_resources_by_prefix('biergarten-dev/');
|
||||||
|
};
|
||||||
|
|
||||||
|
export default clearCloudinaryStorage;
|
||||||
@@ -1,7 +1,16 @@
|
|||||||
import logger from '../../../config/pino/logger';
|
import logger from '../../../config/pino/logger';
|
||||||
|
import clearCloudinaryStorage from './clearCloudinaryStorage';
|
||||||
import clearDatabase from './clearDatabase';
|
import clearDatabase from './clearDatabase';
|
||||||
|
|
||||||
clearDatabase().then(() => {
|
(async () => {
|
||||||
logger.info('Database cleared');
|
await clearDatabase();
|
||||||
process.exit(0);
|
await clearCloudinaryStorage();
|
||||||
});
|
})()
|
||||||
|
.then(() => {
|
||||||
|
logger.info('Successfully cleared database and cloudinary storage.');
|
||||||
|
process.exit(0);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
logger.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import createNewBeerStyleComments from './create/createNewBeerStyleComments';
|
|||||||
import createNewBeerStyleLikes from './create/createNewBeerStyleLikes';
|
import createNewBeerStyleLikes from './create/createNewBeerStyleLikes';
|
||||||
import createNewUserAvatars from './create/createNewUserAvatars';
|
import createNewUserAvatars from './create/createNewUserAvatars';
|
||||||
import createNewUserFollows from './create/createNewUserFollows';
|
import createNewUserFollows from './create/createNewUserFollows';
|
||||||
|
import clearCloudinaryStorage from './clear/clearCloudinaryStorage';
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -27,6 +28,7 @@ import createNewUserFollows from './create/createNewUserFollows';
|
|||||||
|
|
||||||
logger.info('Clearing database.');
|
logger.info('Clearing database.');
|
||||||
await clearDatabase();
|
await clearDatabase();
|
||||||
|
await clearCloudinaryStorage();
|
||||||
logger.info('Database cleared successfully, preparing to seed.');
|
logger.info('Database cleared successfully, preparing to seed.');
|
||||||
|
|
||||||
await createAdminUser();
|
await createAdminUser();
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
import DBClient from '@/prisma/DBClient';
|
|
||||||
import { BeerImage } from '@prisma/client';
|
|
||||||
import { z } from 'zod';
|
|
||||||
import ImageMetadataValidationSchema from '../../schema/ImageSchema/ImageMetadataValidationSchema';
|
|
||||||
|
|
||||||
interface ProcessImageDataArgs {
|
|
||||||
files: Express.Multer.File[];
|
|
||||||
alt: z.infer<typeof ImageMetadataValidationSchema>['alt'];
|
|
||||||
caption: z.infer<typeof ImageMetadataValidationSchema>['caption'];
|
|
||||||
beerPostId: string;
|
|
||||||
userId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const addBeerImageToDB = ({
|
|
||||||
alt,
|
|
||||||
caption,
|
|
||||||
files,
|
|
||||||
beerPostId,
|
|
||||||
userId,
|
|
||||||
}: ProcessImageDataArgs) => {
|
|
||||||
const beerImagePromises: Promise<BeerImage>[] = [];
|
|
||||||
|
|
||||||
files.forEach((file) => {
|
|
||||||
beerImagePromises.push(
|
|
||||||
DBClient.instance.beerImage.create({
|
|
||||||
data: {
|
|
||||||
alt,
|
|
||||||
caption,
|
|
||||||
postedBy: { connect: { id: userId } },
|
|
||||||
beerPost: { connect: { id: beerPostId } },
|
|
||||||
path: file.path,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(beerImagePromises);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default addBeerImageToDB;
|
|
||||||
87
src/services/images/beer-image/index.ts
Normal file
87
src/services/images/beer-image/index.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import DBClient from '@/prisma/DBClient';
|
||||||
|
import { BeerImage } from '@prisma/client';
|
||||||
|
import { cloudinary } from '@/config/cloudinary';
|
||||||
|
import {
|
||||||
|
AddBeerImagesToDB,
|
||||||
|
DeleteBeerImageFromDBAndStorage,
|
||||||
|
UpdateBeerImageMetadata,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds beer images to the database.
|
||||||
|
*
|
||||||
|
* @param options - The options for adding beer images.
|
||||||
|
* @param options.body - The body of the request.
|
||||||
|
* @param options.body.alt - The alt text for the beer image.
|
||||||
|
* @param options.body.caption - The caption for the beer image.
|
||||||
|
* @param options.files - The array of files to be uploaded as beer images.
|
||||||
|
* @param options.beerPostId - The ID of the beer post.
|
||||||
|
* @param options.userId - The ID of the user.
|
||||||
|
* @returns A promise that resolves to an array of created beer images.
|
||||||
|
*/
|
||||||
|
export const addBeerImagesToDB: AddBeerImagesToDB = ({
|
||||||
|
body,
|
||||||
|
files,
|
||||||
|
beerPostId,
|
||||||
|
userId,
|
||||||
|
}) => {
|
||||||
|
const beerImagePromises: Promise<BeerImage>[] = [];
|
||||||
|
|
||||||
|
const { alt, caption } = body;
|
||||||
|
files.forEach((file) => {
|
||||||
|
beerImagePromises.push(
|
||||||
|
DBClient.instance.beerImage.create({
|
||||||
|
data: {
|
||||||
|
alt,
|
||||||
|
caption,
|
||||||
|
postedBy: { connect: { id: userId } },
|
||||||
|
beerPost: { connect: { id: beerPostId } },
|
||||||
|
path: file.path,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(beerImagePromises);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a beer image from the database and storage.
|
||||||
|
*
|
||||||
|
* @param options - The options for deleting a beer image.
|
||||||
|
* @param options.beerImageId - The ID of the beer image.
|
||||||
|
*/
|
||||||
|
export const deleteBeerImageFromDBAndStorage: DeleteBeerImageFromDBAndStorage = async ({
|
||||||
|
beerImageId,
|
||||||
|
}) => {
|
||||||
|
const deleted = await DBClient.instance.beerImage.delete({
|
||||||
|
where: { id: beerImageId },
|
||||||
|
select: { path: true, id: true },
|
||||||
|
});
|
||||||
|
const { path } = deleted;
|
||||||
|
await cloudinary.uploader.destroy(path);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the beer image metadata in the database.
|
||||||
|
*
|
||||||
|
* @param options - The options for updating the beer image metadata.
|
||||||
|
* @param options.beerImageId - The ID of the beer image.
|
||||||
|
* @param options.body - The body of the request containing the alt and caption.
|
||||||
|
* @param options.body.alt - The alt text for the beer image.
|
||||||
|
* @param options.body.caption - The caption for the beer image.
|
||||||
|
* @returns A promise that resolves to the updated beer image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const updateBeerImageMetadata: UpdateBeerImageMetadata = async ({
|
||||||
|
beerImageId,
|
||||||
|
body,
|
||||||
|
}) => {
|
||||||
|
const { alt, caption } = body;
|
||||||
|
const updated = await DBClient.instance.beerImage.update({
|
||||||
|
where: { id: beerImageId },
|
||||||
|
data: { alt, caption },
|
||||||
|
});
|
||||||
|
|
||||||
|
return updated;
|
||||||
|
};
|
||||||
19
src/services/images/beer-image/types/index.ts
Normal file
19
src/services/images/beer-image/types/index.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import ImageMetadataValidationSchema from '@/services/schema/ImageSchema/ImageMetadataValidationSchema';
|
||||||
|
import { BeerImage } from '@prisma/client';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export type AddBeerImagesToDB = (args: {
|
||||||
|
files: Express.Multer.File[];
|
||||||
|
body: z.infer<typeof ImageMetadataValidationSchema>;
|
||||||
|
beerPostId: string;
|
||||||
|
userId: string;
|
||||||
|
}) => Promise<BeerImage[]>;
|
||||||
|
|
||||||
|
export type DeleteBeerImageFromDBAndStorage = (args: {
|
||||||
|
beerImageId: string;
|
||||||
|
}) => Promise<void>;
|
||||||
|
|
||||||
|
export type UpdateBeerImageMetadata = (args: {
|
||||||
|
beerImageId: string;
|
||||||
|
body: z.infer<typeof ImageMetadataValidationSchema>;
|
||||||
|
}) => Promise<BeerImage>;
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import DBClient from '@/prisma/DBClient';
|
|
||||||
import { BreweryImage } from '@prisma/client';
|
|
||||||
import { z } from 'zod';
|
|
||||||
import ImageMetadataValidationSchema from '../../schema/ImageSchema/ImageMetadataValidationSchema';
|
|
||||||
|
|
||||||
interface ProcessImageDataArgs {
|
|
||||||
files: Express.Multer.File[];
|
|
||||||
alt: z.infer<typeof ImageMetadataValidationSchema>['alt'];
|
|
||||||
caption: z.infer<typeof ImageMetadataValidationSchema>['caption'];
|
|
||||||
breweryPostId: string;
|
|
||||||
userId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const addBreweryImageToDB = ({
|
|
||||||
alt,
|
|
||||||
caption,
|
|
||||||
files,
|
|
||||||
breweryPostId,
|
|
||||||
userId,
|
|
||||||
}: ProcessImageDataArgs) => {
|
|
||||||
const breweryImagePromises: Promise<BreweryImage>[] = [];
|
|
||||||
files.forEach((file) => {
|
|
||||||
breweryImagePromises.push(
|
|
||||||
DBClient.instance.breweryImage.create({
|
|
||||||
data: {
|
|
||||||
alt,
|
|
||||||
caption,
|
|
||||||
postedBy: { connect: { id: userId } },
|
|
||||||
breweryPost: { connect: { id: breweryPostId } },
|
|
||||||
path: file.path,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(breweryImagePromises);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default addBreweryImageToDB;
|
|
||||||
86
src/services/images/brewery-image/index.ts
Normal file
86
src/services/images/brewery-image/index.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import DBClient from '@/prisma/DBClient';
|
||||||
|
import { BreweryImage } from '@prisma/client';
|
||||||
|
import { cloudinary } from '@/config/cloudinary';
|
||||||
|
import {
|
||||||
|
AddBreweryImagesToDB,
|
||||||
|
DeleteBreweryImageFromDBAndStorage,
|
||||||
|
UpdateBreweryImageMetadata,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds brewery images to the database.
|
||||||
|
*
|
||||||
|
* @param options - The options for adding brewery images.
|
||||||
|
* @param options.body - The body of the request containing the alt and caption.
|
||||||
|
* @param options.body.alt - The alt text for the brewery image.
|
||||||
|
* @param options.body.caption - The caption for the brewery image.
|
||||||
|
* @param options.files - The array of files to be uploaded as brewery images.
|
||||||
|
* @param options.breweryPostId - The ID of the brewery post.
|
||||||
|
* @param options.userId - The ID of the user adding the images.
|
||||||
|
* @returns A promise that resolves to an array of created brewery images.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const addBreweryImagesToDB: AddBreweryImagesToDB = ({
|
||||||
|
body,
|
||||||
|
files,
|
||||||
|
breweryPostId,
|
||||||
|
userId,
|
||||||
|
}) => {
|
||||||
|
const breweryImagePromises: Promise<BreweryImage>[] = [];
|
||||||
|
|
||||||
|
const { alt, caption } = body;
|
||||||
|
files.forEach((file) => {
|
||||||
|
breweryImagePromises.push(
|
||||||
|
DBClient.instance.breweryImage.create({
|
||||||
|
data: {
|
||||||
|
alt,
|
||||||
|
caption,
|
||||||
|
postedBy: { connect: { id: userId } },
|
||||||
|
breweryPost: { connect: { id: breweryPostId } },
|
||||||
|
path: file.path,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(breweryImagePromises);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a brewery image from the database and storage.
|
||||||
|
*
|
||||||
|
* @param options - The options for deleting a brewery image.
|
||||||
|
* @param options.breweryImageId - The ID of the brewery image.
|
||||||
|
*/
|
||||||
|
export const deleteBreweryImageFromDBAndStorage: DeleteBreweryImageFromDBAndStorage =
|
||||||
|
async ({ breweryImageId }) => {
|
||||||
|
const deleted = await DBClient.instance.breweryImage.delete({
|
||||||
|
where: { id: breweryImageId },
|
||||||
|
select: { path: true, id: true },
|
||||||
|
});
|
||||||
|
const { path } = deleted;
|
||||||
|
await cloudinary.uploader.destroy(path);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the brewery image metadata in the database.
|
||||||
|
*
|
||||||
|
* @param options - The options for updating the brewery image metadata.
|
||||||
|
* @param options.breweryImageId - The ID of the brewery image.
|
||||||
|
* @param options.body - The body of the request containing the alt and caption.
|
||||||
|
* @param options.body.alt - The alt text for the brewery image.
|
||||||
|
* @param options.body.caption - The caption for the brewery image.
|
||||||
|
* @returns A promise that resolves to the updated brewery image.
|
||||||
|
*/
|
||||||
|
export const updateBreweryImageMetadata: UpdateBreweryImageMetadata = async ({
|
||||||
|
breweryImageId,
|
||||||
|
body,
|
||||||
|
}) => {
|
||||||
|
const { alt, caption } = body;
|
||||||
|
const updated = await DBClient.instance.breweryImage.update({
|
||||||
|
where: { id: breweryImageId },
|
||||||
|
data: { alt, caption },
|
||||||
|
});
|
||||||
|
|
||||||
|
return updated;
|
||||||
|
};
|
||||||
19
src/services/images/brewery-image/types/index.ts
Normal file
19
src/services/images/brewery-image/types/index.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import ImageMetadataValidationSchema from '@/services/schema/ImageSchema/ImageMetadataValidationSchema';
|
||||||
|
import { BreweryImage } from '@prisma/client';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export type AddBreweryImagesToDB = (args: {
|
||||||
|
files: Express.Multer.File[];
|
||||||
|
body: z.infer<typeof ImageMetadataValidationSchema>;
|
||||||
|
breweryPostId: string;
|
||||||
|
userId: string;
|
||||||
|
}) => Promise<BreweryImage[]>;
|
||||||
|
|
||||||
|
export type DeleteBreweryImageFromDBAndStorage = (args: {
|
||||||
|
breweryImageId: string;
|
||||||
|
}) => Promise<void>;
|
||||||
|
|
||||||
|
export type UpdateBreweryImageMetadata = (args: {
|
||||||
|
breweryImageId: string;
|
||||||
|
body: z.infer<typeof ImageMetadataValidationSchema>;
|
||||||
|
}) => Promise<BreweryImage>;
|
||||||
Reference in New Issue
Block a user