S3 : add news
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
const News = require("../models/News");
|
||||
const { body, validationResult } = require("express-validator");
|
||||
const sharp = require("sharp");
|
||||
const { _sr } = require("../plugins/serverResponses");
|
||||
const {
|
||||
res404,
|
||||
@@ -14,9 +13,13 @@ const fs = require("fs");
|
||||
const NewsFile = require("../models/NewsFile");
|
||||
const Polls = require("../models/Polls");
|
||||
const moment = require("moment-jalaali");
|
||||
const {
|
||||
getStoredImageName,
|
||||
deleteNewsImage,
|
||||
uploadProcessedImage,
|
||||
} = require("../plugins/newsImageStorage");
|
||||
|
||||
////// variables
|
||||
const noCover = "/img/no-cover.jpg";
|
||||
const coverNewsWidth = 1920;
|
||||
const coverNewsHeight = 1080;
|
||||
const coverQuality = 100;
|
||||
@@ -111,31 +114,23 @@ const handleFileUploads = async (req, res, targetNews) => {
|
||||
|
||||
if (req.files.cover) {
|
||||
const image = req.files.cover;
|
||||
if (!_sr.supportedImageFormats.includes(image.mimetype.split("/")[1])) {
|
||||
if (!validateNewsImage(image)) {
|
||||
throw new Error(_sr["fa"].format.image);
|
||||
}
|
||||
|
||||
// حذف کاور قدیمی در صورت وجود
|
||||
if (targetNews.cover && targetNews.cover !== noCover) {
|
||||
const oldCoverPath = `./static/uploads/images/news/${targetNews.cover}`;
|
||||
if (fs.existsSync(oldCoverPath)) {
|
||||
fs.unlinkSync(oldCoverPath);
|
||||
}
|
||||
}
|
||||
await deleteNewsImage(targetNews, "cover");
|
||||
|
||||
const imageName = `news_cover_${timestamp}_${targetNews._id}.${
|
||||
image.mimetype.split("/")[1]
|
||||
}`;
|
||||
try {
|
||||
const target = sharp(image.data);
|
||||
await target
|
||||
.resize(coverNewsWidth, coverNewsHeight, {
|
||||
fit: "cover",
|
||||
})
|
||||
.jpeg({
|
||||
quality: coverQuality,
|
||||
})
|
||||
.toFile(`./static/uploads/images/news/${imageName}`);
|
||||
await processAndUploadNewsImage(
|
||||
image.data,
|
||||
imageName,
|
||||
coverNewsWidth,
|
||||
coverNewsHeight,
|
||||
coverQuality
|
||||
);
|
||||
|
||||
targetNews.cover = imageName;
|
||||
hasCover = true;
|
||||
@@ -143,28 +138,20 @@ const handleFileUploads = async (req, res, targetNews) => {
|
||||
throw new Error(e?.message);
|
||||
}
|
||||
|
||||
// اگر thumbCover ارسال نشده، از همین تصویر thumbCover بسازیم
|
||||
if (!req.files.thumbCover) {
|
||||
if (targetNews.thumbCover && targetNews.thumbCover !== noCover) {
|
||||
const oldThumbPath = `./static/uploads/images/news/${targetNews.thumbCover}`;
|
||||
if (fs.existsSync(oldThumbPath)) {
|
||||
fs.unlinkSync(oldThumbPath);
|
||||
}
|
||||
}
|
||||
await deleteNewsImage(targetNews, "thumbCover");
|
||||
|
||||
const thumbImageName = `news_thumb_${timestamp}_${targetNews._id}.${
|
||||
image.mimetype.split("/")[1]
|
||||
}`;
|
||||
try {
|
||||
const target = sharp(image.data);
|
||||
await target
|
||||
.resize(thumbCoverNewsWidth, thumbCoverNewsHeight, {
|
||||
fit: "cover",
|
||||
})
|
||||
.jpeg({
|
||||
quality: thumbCoverQuality,
|
||||
})
|
||||
.toFile(`./static/uploads/images/news/${thumbImageName}`);
|
||||
await processAndUploadNewsImage(
|
||||
image.data,
|
||||
thumbImageName,
|
||||
thumbCoverNewsWidth,
|
||||
thumbCoverNewsHeight,
|
||||
thumbCoverQuality
|
||||
);
|
||||
|
||||
targetNews.thumbCover = thumbImageName;
|
||||
hasThumb = true;
|
||||
@@ -176,31 +163,23 @@ const handleFileUploads = async (req, res, targetNews) => {
|
||||
|
||||
if (req.files.thumbCover) {
|
||||
const image = req.files.thumbCover;
|
||||
if (!_sr.supportedImageFormats.includes(image.mimetype.split("/")[1])) {
|
||||
if (!validateNewsImage(image)) {
|
||||
throw new Error(_sr["fa"].format.image);
|
||||
}
|
||||
|
||||
// حذف thumb قدیمی در صورت وجود
|
||||
if (targetNews.thumbCover && targetNews.thumbCover !== noCover) {
|
||||
const oldThumbPath = `./static/uploads/images/news/${targetNews.thumbCover}`;
|
||||
if (fs.existsSync(oldThumbPath)) {
|
||||
fs.unlinkSync(oldThumbPath);
|
||||
}
|
||||
}
|
||||
await deleteNewsImage(targetNews, "thumbCover");
|
||||
|
||||
const thumbImageName = `news_thumb_${timestamp}_${targetNews._id}.${
|
||||
image.mimetype.split("/")[1]
|
||||
}`;
|
||||
try {
|
||||
const target = sharp(image.data);
|
||||
await target
|
||||
.resize(thumbCoverNewsWidth, thumbCoverNewsHeight, {
|
||||
fit: "cover",
|
||||
})
|
||||
.jpeg({
|
||||
quality: thumbCoverQuality,
|
||||
})
|
||||
.toFile(`./static/uploads/images/news/${thumbImageName}`);
|
||||
await processAndUploadNewsImage(
|
||||
image.data,
|
||||
thumbImageName,
|
||||
thumbCoverNewsWidth,
|
||||
thumbCoverNewsHeight,
|
||||
thumbCoverQuality
|
||||
);
|
||||
|
||||
targetNews.thumbCover = thumbImageName;
|
||||
hasThumb = true;
|
||||
@@ -208,28 +187,20 @@ const handleFileUploads = async (req, res, targetNews) => {
|
||||
throw new Error(e?.message);
|
||||
}
|
||||
|
||||
// اگر cover ارسال نشده، از همین تصویر cover بسازیم
|
||||
if (!req.files.cover) {
|
||||
if (targetNews.cover && targetNews.cover !== noCover) {
|
||||
const oldCoverPath = `./static/uploads/images/news/${targetNews.cover}`;
|
||||
if (fs.existsSync(oldCoverPath)) {
|
||||
fs.unlinkSync(oldCoverPath);
|
||||
}
|
||||
}
|
||||
await deleteNewsImage(targetNews, "cover");
|
||||
|
||||
const coverImageName = `news_cover_${timestamp}_${targetNews._id}.${
|
||||
image.mimetype.split("/")[1]
|
||||
}`;
|
||||
try {
|
||||
const target = sharp(image.data);
|
||||
await target
|
||||
.resize(coverNewsWidth, coverNewsHeight, {
|
||||
fit: "cover",
|
||||
})
|
||||
.jpeg({
|
||||
quality: coverQuality,
|
||||
})
|
||||
.toFile(`./static/uploads/images/news/${coverImageName}`);
|
||||
await processAndUploadNewsImage(
|
||||
image.data,
|
||||
coverImageName,
|
||||
coverNewsWidth,
|
||||
coverNewsHeight,
|
||||
coverQuality
|
||||
);
|
||||
|
||||
targetNews.cover = coverImageName;
|
||||
hasCover = true;
|
||||
@@ -239,14 +210,24 @@ const handleFileUploads = async (req, res, targetNews) => {
|
||||
}
|
||||
}
|
||||
|
||||
// بهروزرسانی وضعیت خبر - خبر کامل است اگر حداقل یکی از تصاویر آپلود شده باشد یا قبلاً موجود باشد
|
||||
const currentHasCover = targetNews.cover && targetNews.cover !== noCover;
|
||||
const currentHasThumb =
|
||||
targetNews.thumbCover && targetNews.thumbCover !== noCover;
|
||||
const currentHasCover = getStoredImageName(targetNews, "cover");
|
||||
const currentHasThumb = getStoredImageName(targetNews, "thumbCover");
|
||||
targetNews.newsStatus =
|
||||
hasCover || hasThumb || currentHasCover || currentHasThumb;
|
||||
};
|
||||
|
||||
const processAndUploadNewsImage = async (
|
||||
imageData,
|
||||
imageName,
|
||||
width,
|
||||
height,
|
||||
quality
|
||||
) => uploadProcessedImage(imageData, imageName, width, height, quality);
|
||||
|
||||
const validateNewsImage = (image) => {
|
||||
return _sr.supportedImageFormats.includes(image.mimetype.split("/")[1]);
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// admin
|
||||
module.exports.addNews = [
|
||||
[
|
||||
@@ -488,9 +469,7 @@ module.exports.addNews = [
|
||||
|
||||
if (req.files.cover) {
|
||||
const image = req.files.cover;
|
||||
if (
|
||||
!_sr.supportedImageFormats.includes(image.mimetype.split("/")[1])
|
||||
) {
|
||||
if (!validateNewsImage(image)) {
|
||||
return res.status(422).json({
|
||||
validation: {
|
||||
cover: {
|
||||
@@ -503,15 +482,13 @@ module.exports.addNews = [
|
||||
image.mimetype.split("/")[1]
|
||||
}`;
|
||||
try {
|
||||
const target = sharp(image.data);
|
||||
await target
|
||||
.resize(coverNewsWidth, coverNewsHeight, {
|
||||
fit: "cover",
|
||||
})
|
||||
.jpeg({
|
||||
quality: coverQuality,
|
||||
})
|
||||
.toFile(`./static/uploads/images/news/${imageName}`);
|
||||
await processAndUploadNewsImage(
|
||||
image.data,
|
||||
imageName,
|
||||
coverNewsWidth,
|
||||
coverNewsHeight,
|
||||
coverQuality
|
||||
);
|
||||
|
||||
createNews.cover = imageName;
|
||||
hasCover = true;
|
||||
@@ -519,21 +496,18 @@ module.exports.addNews = [
|
||||
return res500(res, e?.message);
|
||||
}
|
||||
|
||||
// اگر thumbCover ارسال نشده، از همین تصویر thumbCover بسازیم
|
||||
if (!req.files.thumbCover) {
|
||||
const thumbImageName = `news_thumb_${timestamp}_${createNews._id}.${
|
||||
image.mimetype.split("/")[1]
|
||||
}`;
|
||||
try {
|
||||
const target = sharp(image.data);
|
||||
await target
|
||||
.resize(thumbCoverNewsWidth, thumbCoverNewsHeight, {
|
||||
fit: "cover",
|
||||
})
|
||||
.jpeg({
|
||||
quality: thumbCoverQuality,
|
||||
})
|
||||
.toFile(`./static/uploads/images/news/${thumbImageName}`);
|
||||
await processAndUploadNewsImage(
|
||||
image.data,
|
||||
thumbImageName,
|
||||
thumbCoverNewsWidth,
|
||||
thumbCoverNewsHeight,
|
||||
thumbCoverQuality
|
||||
);
|
||||
|
||||
createNews.thumbCover = thumbImageName;
|
||||
hasThumb = true;
|
||||
@@ -545,9 +519,7 @@ module.exports.addNews = [
|
||||
|
||||
if (req.files.thumbCover) {
|
||||
const image = req.files.thumbCover;
|
||||
if (
|
||||
!_sr.supportedImageFormats.includes(image.mimetype.split("/")[1])
|
||||
) {
|
||||
if (!validateNewsImage(image)) {
|
||||
return res.status(422).json({
|
||||
validation: {
|
||||
thumbCover: {
|
||||
@@ -560,15 +532,13 @@ module.exports.addNews = [
|
||||
image.mimetype.split("/")[1]
|
||||
}`;
|
||||
try {
|
||||
const target = sharp(image.data);
|
||||
await target
|
||||
.resize(thumbCoverNewsWidth, thumbCoverNewsHeight, {
|
||||
fit: "cover",
|
||||
})
|
||||
.jpeg({
|
||||
quality: thumbCoverQuality,
|
||||
})
|
||||
.toFile(`./static/uploads/images/news/${thumbImageName}`);
|
||||
await processAndUploadNewsImage(
|
||||
image.data,
|
||||
thumbImageName,
|
||||
thumbCoverNewsWidth,
|
||||
thumbCoverNewsHeight,
|
||||
thumbCoverQuality
|
||||
);
|
||||
|
||||
createNews.thumbCover = thumbImageName;
|
||||
hasThumb = true;
|
||||
@@ -576,21 +546,18 @@ module.exports.addNews = [
|
||||
return res500(res, e?.message);
|
||||
}
|
||||
|
||||
// اگر cover ارسال نشده، از همین تصویر cover بسازیم
|
||||
if (!req.files.cover) {
|
||||
const coverImageName = `news_cover_${timestamp}_${createNews._id}.${
|
||||
image.mimetype.split("/")[1]
|
||||
}`;
|
||||
try {
|
||||
const target = sharp(image.data);
|
||||
await target
|
||||
.resize(coverNewsWidth, coverNewsHeight, {
|
||||
fit: "cover",
|
||||
})
|
||||
.jpeg({
|
||||
quality: coverQuality,
|
||||
})
|
||||
.toFile(`./static/uploads/images/news/${coverImageName}`);
|
||||
await processAndUploadNewsImage(
|
||||
image.data,
|
||||
coverImageName,
|
||||
coverNewsWidth,
|
||||
coverNewsHeight,
|
||||
coverQuality
|
||||
);
|
||||
|
||||
createNews.cover = coverImageName;
|
||||
hasCover = true;
|
||||
@@ -600,7 +567,6 @@ module.exports.addNews = [
|
||||
}
|
||||
}
|
||||
|
||||
// خبر کامل است اگر حداقل یکی از تصاویر آپلود شده باشد
|
||||
createNews.newsStatus = hasCover || hasThumb;
|
||||
await createNews.save();
|
||||
}
|
||||
@@ -987,30 +953,13 @@ module.exports.deletOneNews = [
|
||||
return res500(res, `شما اجازه حذف این خبر را ندارید`);
|
||||
}
|
||||
|
||||
if (targetNews.cover !== noCover) {
|
||||
oldPic = `./static${targetNews.cover}`;
|
||||
|
||||
if (fs.existsSync(oldPic)) {
|
||||
fs.unlink(oldPic, (error) => {
|
||||
if (error) return res500(res, error?.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (targetNews.thumbCover !== noCover) {
|
||||
oldPic = `./static${targetNews.thumbCover}`;
|
||||
|
||||
if (fs.existsSync(oldPic)) {
|
||||
fs.unlink(oldPic, (error) => {
|
||||
if (error) return res500(res, error?.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
await deleteNewsImage(targetNews, "cover");
|
||||
await deleteNewsImage(targetNews, "thumbCover");
|
||||
|
||||
await targetNews.deleteOne();
|
||||
|
||||
await Comment.deleteMany({ modelRef: targetNews._id });
|
||||
x;
|
||||
|
||||
return res.json(targetNews);
|
||||
} catch (error) {
|
||||
return res500(res, error);
|
||||
|
||||
@@ -4,11 +4,12 @@ const {_sr} = require('../plugins/serverResponses')
|
||||
const {res404, res500} = require('../plugins/controllersHelperFunctions')
|
||||
const News = require('../models/News')
|
||||
const Category = require('../models/Category')
|
||||
const sharp = require('sharp')
|
||||
const fs = require('fs')
|
||||
const {
|
||||
deleteNewsImage,
|
||||
uploadProcessedImage,
|
||||
} = require('../plugins/newsImageStorage')
|
||||
|
||||
////// variables
|
||||
const noCover = '/img/no-cover.jpg'
|
||||
const limit = 5;
|
||||
const limitDetails = 11;
|
||||
const titleFilterRegex = new RegExp('/', 'g')
|
||||
@@ -187,19 +188,23 @@ module.exports.addNewsFile = [
|
||||
})
|
||||
const imageName = `news_${Date.now()}_${createNewsFile._id}.${image.mimetype.split('/')[1]}`;
|
||||
try {
|
||||
const target = sharp(image.data)
|
||||
await target
|
||||
.resize(coverNewsWidth, coverNewsHeight, {fit: 'cover'})
|
||||
.jpeg({quality: coverQuality})
|
||||
.toFile(`./static/uploads/images/news/${imageName}`);
|
||||
await uploadProcessedImage(
|
||||
image.data,
|
||||
imageName,
|
||||
coverNewsWidth,
|
||||
coverNewsHeight,
|
||||
coverQuality
|
||||
);
|
||||
|
||||
await uploadProcessedImage(
|
||||
image.data,
|
||||
`thumb_${imageName}`,
|
||||
thumbCoverNewsWidth,
|
||||
thumbCoverNewsHeight,
|
||||
thumbCoverQuality
|
||||
);
|
||||
|
||||
createNewsFile.cover = imageName;
|
||||
|
||||
await target
|
||||
.resize(thumbCoverNewsWidth, thumbCoverNewsHeight, {fit: 'cover'})
|
||||
.jpeg({quality: thumbCoverQuality})
|
||||
.toFile(`./static/uploads/images/news/thumb_${imageName}`);
|
||||
|
||||
createNewsFile.thumbCover = `thumb_${imageName}`;
|
||||
|
||||
await createNewsFile.save();
|
||||
@@ -375,39 +380,24 @@ module.exports.updateNewsFile = [
|
||||
}
|
||||
const imageName = `news_${Date.now()}_${targetNewsFile._id}.${image.mimetype.split('/')[1]}`;
|
||||
try {
|
||||
const target = sharp(image.data)
|
||||
await target
|
||||
.resize(coverNewsWidth, coverNewsHeight, {fit: 'cover'})
|
||||
.jpeg({quality: coverQuality})
|
||||
.toFile(`./static/uploads/images/news/${imageName}`);
|
||||
await deleteNewsImage(targetNewsFile, "cover");
|
||||
await deleteNewsImage(targetNewsFile, "thumbCover");
|
||||
|
||||
await target
|
||||
.resize(thumbCoverNewsWidth, thumbCoverNewsHeight, {fit: 'cover'})
|
||||
.jpeg({quality: thumbCoverQuality})
|
||||
.toFile(`./static/uploads/images/news/thumb_${imageName}`);
|
||||
await uploadProcessedImage(
|
||||
image.data,
|
||||
imageName,
|
||||
coverNewsWidth,
|
||||
coverNewsHeight,
|
||||
coverQuality
|
||||
);
|
||||
|
||||
/**
|
||||
* if exist old pic delete it from file
|
||||
*/
|
||||
if (targetNewsFile.cover !== noCover) {
|
||||
let oldPic = `./static${targetNewsFile.cover}`;
|
||||
|
||||
if (await fs.existsSync(oldPic)) {
|
||||
fs.unlink(oldPic, (err) => {
|
||||
if (err) return res500(res, err?.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (targetNewsFile.thumbCover !== noCover) {
|
||||
let oldPic = `./static${targetNewsFile.thumbCover}`;
|
||||
|
||||
if (await fs.existsSync(oldPic)) {
|
||||
fs.unlink(oldPic, (err) => {
|
||||
if (err) return res500(res, err?.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
await uploadProcessedImage(
|
||||
image.data,
|
||||
`thumb_${imageName}`,
|
||||
thumbCoverNewsWidth,
|
||||
thumbCoverNewsHeight,
|
||||
thumbCoverQuality
|
||||
);
|
||||
|
||||
targetNewsFile.cover = imageName;
|
||||
targetNewsFile.thumbCover = `thumb_${imageName}`;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require("dotenv").config();
|
||||
|
||||
const express = require("express");
|
||||
const database = require("./database");
|
||||
const fileUpload = require("express-fileupload");
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
const mongoose = require('mongoose');
|
||||
const mongoosePaginate = require('mongoose-paginate-v2');
|
||||
const s3Storage = require('../plugins/s3Storage');
|
||||
|
||||
function image(img) {
|
||||
if (img) return '/uploads/images/news/' + img
|
||||
else return '/img/no-cover.jpg'
|
||||
if (!img) return '/img/no-cover.jpg';
|
||||
if (img.startsWith('http://') || img.startsWith('https://')) return img;
|
||||
return s3Storage.getPublicUrl(`uploads/images/news/${img}`);
|
||||
}
|
||||
|
||||
function file(file) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
const mongoose = require('mongoose');
|
||||
const mongoosePaginate = require('mongoose-paginate-v2');
|
||||
const s3Storage = require('../plugins/s3Storage');
|
||||
|
||||
function image(img) {
|
||||
if (img) return '/uploads/images/news/' + img
|
||||
else return '/img/no-cover.jpg'
|
||||
if (!img) return '/img/no-cover.jpg';
|
||||
if (img.startsWith('http://') || img.startsWith('https://')) return img;
|
||||
return s3Storage.getPublicUrl(`uploads/images/news/${img}`);
|
||||
}
|
||||
|
||||
const NewsFileSchema = mongoose.Schema({
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
const sharp = require("sharp");
|
||||
const s3Storage = require("./s3Storage");
|
||||
|
||||
const NEWS_IMAGE_PREFIX = "uploads/images/news";
|
||||
|
||||
const getStoredImageName = (doc, field) =>
|
||||
doc.get(field, null, { getters: false });
|
||||
|
||||
const deleteNewsImage = async (doc, field) => {
|
||||
const fileName = getStoredImageName(doc, field);
|
||||
if (!fileName) return;
|
||||
|
||||
try {
|
||||
await s3Storage.deleteObject(`${NEWS_IMAGE_PREFIX}/${fileName}`);
|
||||
} catch (error) {
|
||||
console.log(`Failed to delete ${field} from S3:`, error?.message);
|
||||
}
|
||||
};
|
||||
|
||||
const uploadProcessedImage = async (
|
||||
imageData,
|
||||
imageName,
|
||||
width,
|
||||
height,
|
||||
quality
|
||||
) => {
|
||||
const buffer = await sharp(imageData)
|
||||
.resize(width, height, { fit: "cover" })
|
||||
.jpeg({ quality })
|
||||
.toBuffer();
|
||||
|
||||
await s3Storage.uploadBuffer(
|
||||
`${NEWS_IMAGE_PREFIX}/${imageName}`,
|
||||
buffer,
|
||||
"image/jpeg"
|
||||
);
|
||||
|
||||
return imageName;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
NEWS_IMAGE_PREFIX,
|
||||
getStoredImageName,
|
||||
deleteNewsImage,
|
||||
uploadProcessedImage,
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
const {
|
||||
S3Client,
|
||||
PutObjectCommand,
|
||||
DeleteObjectCommand,
|
||||
} = require("@aws-sdk/client-s3");
|
||||
|
||||
const config = {
|
||||
bucket: process.env.BUCKET_NAME,
|
||||
region: process.env.BUCKET_REGION || "us-west-2",
|
||||
endpoint: process.env.PARSPACK_S3_ENDPOINT,
|
||||
accessKeyId: process.env.BUCKET_ACCESS_KEY,
|
||||
secretAccessKey: process.env.BUCKET_SECRET_KEY,
|
||||
publicUrl: process.env.BUCKET_PUBLIC_URL || process.env.PARSPACK_S3_ENDPOINT,
|
||||
};
|
||||
|
||||
let s3Client = null;
|
||||
|
||||
const isConfigured = () =>
|
||||
Boolean(
|
||||
config.bucket &&
|
||||
config.endpoint &&
|
||||
config.accessKeyId &&
|
||||
config.secretAccessKey
|
||||
);
|
||||
|
||||
const getClient = () => {
|
||||
if (!isConfigured()) {
|
||||
throw new Error("S3 storage is not configured");
|
||||
}
|
||||
|
||||
if (!s3Client) {
|
||||
s3Client = new S3Client({
|
||||
region: config.region,
|
||||
endpoint: config.endpoint,
|
||||
credentials: {
|
||||
accessKeyId: config.accessKeyId,
|
||||
secretAccessKey: config.secretAccessKey,
|
||||
},
|
||||
forcePathStyle: true,
|
||||
});
|
||||
}
|
||||
|
||||
return s3Client;
|
||||
};
|
||||
|
||||
const normalizeKey = (key) => key.replace(/^\/+/, "");
|
||||
|
||||
const getPublicUrl = (key) => {
|
||||
const normalizedKey = normalizeKey(key);
|
||||
const baseUrl = (config.publicUrl || config.endpoint).replace(/\/+$/, "");
|
||||
return `${baseUrl}/${normalizedKey}`;
|
||||
};
|
||||
|
||||
const uploadBuffer = async (
|
||||
key,
|
||||
buffer,
|
||||
contentType = "application/octet-stream"
|
||||
) => {
|
||||
const normalizedKey = normalizeKey(key);
|
||||
|
||||
await getClient().send(
|
||||
new PutObjectCommand({
|
||||
Bucket: config.bucket,
|
||||
Key: normalizedKey,
|
||||
Body: buffer,
|
||||
ContentType: contentType,
|
||||
ACL: "public-read",
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
key: normalizedKey,
|
||||
url: getPublicUrl(normalizedKey),
|
||||
};
|
||||
};
|
||||
|
||||
const deleteObject = async (key) => {
|
||||
const normalizedKey = normalizeKey(key);
|
||||
|
||||
await getClient().send(
|
||||
new DeleteObjectCommand({
|
||||
Bucket: config.bucket,
|
||||
Key: normalizedKey,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
isConfigured,
|
||||
getPublicUrl,
|
||||
uploadBuffer,
|
||||
deleteObject,
|
||||
};
|
||||
+12
-7
@@ -1,18 +1,24 @@
|
||||
const axios = require("axios");
|
||||
|
||||
const SMS_API_KEY = "QkkNxhyXZ6GtEf1soOTtikomO3mA4LaNQDH8mol8huDIwh00";
|
||||
|
||||
module.exports.sms = async (phoneNumber, message) => {
|
||||
const smsService = new SmsService("QkkNxhyXZ6GtEf1soOTtikomO3mA4LaNQDH8mol8huDIwh00");
|
||||
const smsService = new SmsService(SMS_API_KEY);
|
||||
return smsService.sendMessage(phoneNumber, message);
|
||||
};
|
||||
|
||||
/** Sends login/verification OTP via sms.ir template (verify endpoint). */
|
||||
module.exports.sendOtpSms = async (phoneNumber, otp) => {
|
||||
const smsService = new SmsService(SMS_API_KEY);
|
||||
return smsService.sendOTPSms(otp, phoneNumber);
|
||||
};
|
||||
|
||||
class SmsService {
|
||||
constructor(apiKey) {
|
||||
this.API_URL = "https://api.sms.ir/v1";
|
||||
this.OTP_PATTERN = "83604";
|
||||
this.OTP_PATTERN = "628767";
|
||||
this.SMS_API_KEY = apiKey;
|
||||
}
|
||||
//******************************** */
|
||||
|
||||
//******************************** */
|
||||
|
||||
async sendMessage(phone, message) {
|
||||
try {
|
||||
@@ -32,7 +38,7 @@ class SmsService {
|
||||
console.error("Error in sending SMS", error);
|
||||
}
|
||||
}
|
||||
//******************************** */
|
||||
|
||||
async getLineNumber() {
|
||||
try {
|
||||
const { data } = await axios.get(`${this.API_URL}/line`, {
|
||||
@@ -45,7 +51,6 @@ class SmsService {
|
||||
console.error("Error in getting line number", error);
|
||||
}
|
||||
}
|
||||
//******************************** */
|
||||
|
||||
async sendOTPSms(otp, phone) {
|
||||
const smsData = {
|
||||
|
||||
Reference in New Issue
Block a user