Skip to content

Commit

Permalink
Added method to write stream with prefix in case of writing to S3 bucket
Browse files Browse the repository at this point in the history
  • Loading branch information
deelanM committed Apr 13, 2021
1 parent b638410 commit f294ee3
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 99 deletions.
2 changes: 2 additions & 0 deletions packages/server/common/file-manage.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const {
streamImage,
writeStreamFromPath,
writeStreamFromStream,
writeStreamFromStreamWithPrefix,
listImages,
copyImages,
} = require(config.isAws ? '../utils/storage-s3' : '../utils/storage-local');
Expand Down Expand Up @@ -129,4 +130,5 @@ module.exports = {
copyImages,
writeStreamFromPath,
writeStreamFromStream,
writeStreamFromStreamWithPrefix
};
2 changes: 0 additions & 2 deletions packages/server/image/image.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,6 @@ async function create(req, res) {
});
safeGallery.files = galleryImages;

console.log({galleryFiles: safeGallery.files})

safeGallery.markModified('files');
await safeGallery.save();

Expand Down
44 changes: 9 additions & 35 deletions packages/server/mailing/mailing.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ module.exports = {
bulkDestroy: asyncHandler(bulkDestroy),
delete: asyncHandler(deleteMailing),
transferToUser: asyncHandler(transferToUser),
previewMail: asyncHandler(previewMail),
// already wrapped in asyncHandler
sendTestMail,
downloadZip,
Expand Down Expand Up @@ -73,7 +72,7 @@ async function list(req, res) {
*/

async function create(req, res) {
const { user } = req;
const { user, cookies } = req;
const { templateId, workspaceId, parentFolderId, mailingName } = req.body;

const response = await mailingService.createInsideWorkspaceOrFolder({
Expand All @@ -82,7 +81,7 @@ async function create(req, res) {
parentFolderId,
mailingName,
user,
});
}, cookies);

res.json(response);
}
Expand Down Expand Up @@ -308,7 +307,10 @@ async function updateMosaico(req, res) {
const { mailingId } = req.params;
const query = modelsUtils.addGroupFilter(req.user, { _id: mailingId });
const mailing = await Mailings.findOne(query);
if (!mailing) throw new createError.NotFound();

if (!mailing) {
throw new createError.NotFound();
}

mailing.data = req.body.data || mailing.data;
mailing.name =
Expand All @@ -322,6 +324,9 @@ async function updateMosaico(req, res) {
query,
req.user.lang
);

mailingService.generateMailingPreview(mailingId, req.cookies);

res.json(mailingForMosaico);
}

Expand Down Expand Up @@ -496,34 +501,3 @@ async function transferToUser(req, res) {
const response = updatedMailing.toJSON();
res.json(response);
}

/**
* @api {put} /mailings/:mailingId/preview mailing preview from mosaico
* @apiPermission user
* @apiName PreviewMailingForMosaico
* @apiGroup Mailings
*
* @apiParam {string} mailingId
*
* @apiUse mailings
*/

async function previewMail(req, res) {
const { cookies, params } = req;
const { mailingId } = params || {};
const query = modelsUtils.addGroupFilter(req.user, { _id: mailingId });
const mailingForMosaico = await Mailings.findOneForMosaico(
query,
req.user.lang
);

if (!mailingForMosaico) throw new createError.NotFound();

const response = await generatePreview.previewMail({
mailingId,
cookies,
mailingForMosaico,
});
res.setHeader('Content-Type', 'image/png');
res.end(response);
}
1 change: 0 additions & 1 deletion packages/server/mailing/mailing.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ router.post(
);
router.put('/:mailingId/mosaico', GUARD_USER, mailings.updateMosaico);
router.get('/:mailingId/mosaico', GUARD_USER, mailings.readMosaico);
router.get('/:mailingId/preview', GUARD_USER, mailings.previewMail);
router.post('/:mailingId/duplicate', GUARD_USER, mailings.duplicate);
router.post(
'/:mailingId/transfer-to-user',
Expand Down
10 changes: 2 additions & 8 deletions packages/server/mailing/mailing.schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,8 @@ const MailingSchema = Schema(
set: normalizeString,
required: true,
},
files: {
type: [],
// make sure we have the right format for a gallery
get: (files) => {
return files.map((file) =>
formatFilenameForJqueryFileupload(file.name)
);
},
previewFileUrl: {
type: String
},
// _user can't be required: admin doesn't set a _user
_user: { type: ObjectId, ref: UserModel, alias: 'userId' },
Expand Down
17 changes: 11 additions & 6 deletions packages/server/mailing/mailing.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const ERROR_CODES = require('../constant/error-codes.js');
const templateService = require('../template/template.service.js');
const folderService = require('../folder/folder.service.js');
const workspaceService = require('../workspace/workspace.service.js');
const generatePreview = require('../template/generate-preview.controller.js')

module.exports = {
createMailing,
Expand All @@ -41,6 +42,7 @@ module.exports = {
findAllIn,
createInsideWorkspaceOrFolder,
listMailingForWorkspaceOrFolder,
generateMailingPreview
};

async function listMailingForWorkspaceOrFolder({
Expand Down Expand Up @@ -106,7 +108,7 @@ async function findOne(mailingId) {
}

// create a mail inside a workspace or a folder ( depending on the parameters provided )
async function createInsideWorkspaceOrFolder(mailingData) {
async function createInsideWorkspaceOrFolder(mailingData, cookies) {
const {
templateId,
workspaceId,
Expand Down Expand Up @@ -156,11 +158,7 @@ async function createInsideWorkspaceOrFolder(mailingData) {

const newMailing = await createMailing(mailing);

generatePreview.previewMail({
mailingId: mongoose.Types.ObjectId(newMailing._id),
cookies,
})

generateMailingPreview(newMailing._id, cookies);

// strangely toJSON doesn't render the data object
// • cope with that by manually copy it in the response
Expand All @@ -170,6 +168,13 @@ async function createInsideWorkspaceOrFolder(mailingData) {
return response;
}

async function generateMailingPreview(mailingId, cookies) {
await generatePreview.previewMail({
mailingId: mongoose.Types.ObjectId(mailingId._id),
cookies,
})
}

function checkCreationPayload(mailings) {
const { templateId, workspaceId, parentFolderId, mailingName } = mailings;

Expand Down
62 changes: 38 additions & 24 deletions packages/server/template/generate-preview.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,43 @@ async function createPreviews({ templateId, cookies }) {
}
}

async function storePreview(mailingId, preview) {

const { previewFileUrl, _company } = await Mailings.findOne({
_id: mongoose.Types.ObjectId(mailingId),
});

const file = {
name: previewFileUrl,
path: path.join(config.images.tmpDir, `/${previewFileUrl}`)
}

if (!previewFileUrl) {
const hash = crypto.createHash('md5').update(preview).digest('hex');
const name = `${mailingId}-${hash}.png`;
const filePath = path.join(config.images.tmpDir, `/${name}`);

file.name = name;
file.path = filePath;
}

await fs.writeFile(file.path, preview);

const stream = await fs.createReadStream(file.path);

if (config.isAws) {
const prefix = `groups/${_company}/mailings/${mailingId}/preview`;
await fileManager.writeStreamFromStreamWithPrefix(stream, file.name, prefix);
} else {
await fileManager.writeStreamFromStream(stream, file.name);
}

await Mailings.updateOne(
{ _id: mongoose.Types.ObjectId(mailingId) },
{ previewFileUrl: file.name }
);
}

async function previewMail({ mailingId, cookies }) {
const browser = await getHeadlessBrowser();
try {
Expand Down Expand Up @@ -410,31 +447,8 @@ async function previewMail({ mailingId, cookies }) {

await browser.close();

// files
const hash = crypto.createHash('md5').update(screenShot).digest('hex');
const name = `${mailingId}-${hash}.png`;
const filePath = path.join(config.images.tmpDir, `/${name}`);
await storePreview(mailingId, screenShot);

console.log({ filePath });
const file = {
path: filePath,
name,
};
fs.writeFile(filePath, screenShot);

// ----- UPLOAD SCREENSHOTS
const pipeline = sharp().resize(340, null);
fs.createReadStream(file.path).pipe(pipeline);
fileManager.writeStreamFromStream(pipeline, file.name);

const mailing = await Mailings.findById(mongoose.Types.ObjectId(mailingId));

console.log({mailing, file})
mailing.files.push({ ...file });
console.log({files: mailing.files})
mailing.markModified('files');
await mailing.save();
// files
return screenShot;
} catch (error) {
// close browser even if there is a problem
Expand Down
27 changes: 27 additions & 0 deletions packages/server/utils/storage-s3.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,32 @@ if (!config.isAws) {
return deferred;
};

const writeStreamFromStreamWithPrefix = (source, name, prefix) => {
const deferred = defer();

s3.upload(
{
Bucket: config.storage.aws.bucketName,
Prefix: prefix,
Key: name,
Body: source,
},
(err, data) => {
console.log(err, data);
}
)
.on('httpUploadProgress', (progress) => {
console.log(
`writeStreamFromStream – ${name}`,
(progress.loaded / progress.total) * 100
);
if (progress.loaded >= progress.total) deferred.resolve();
})
.on('error', deferred.reject);

return deferred;
};

// http:https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#listObjectsV2-property
// https://github.com/matthew-andrews/denodeify#advanced-usage
const listObjectsV2 = denodeify(s3.listObjectsV2.bind(s3), (err, data) => {
Expand Down Expand Up @@ -119,6 +145,7 @@ if (!config.isAws) {
streamImage,
writeStreamFromPath,
writeStreamFromStream,
writeStreamFromStreamWithPrefix,
listImages,
copyImages,
};
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/helpers/api-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ export function imagesItem(routeParams = {}) {
export function imagesPlaceholder(routeParams = {}) {
return `${API_PREFIX}/images/placeholder/${routeParams.width}x${routeParams.height}.png`;
}
export function images(preview) {
return `${API_PREFIX}/images/${preview}`;
}

/// ///
// WORKSPACEs
Expand Down
40 changes: 17 additions & 23 deletions packages/ui/routes/mailings/__partials/preview-mail.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script>
import { preview } from '~/helpers/api-routes.js';
import { images } from '~/helpers/api-routes';
export default {
name: 'PreviewMail',
Expand All @@ -9,27 +9,20 @@ export default {
},
data() {
return {
images,
loading: false,
errorPreview: false,
previewImage: null,
};
},
async mounted() {
try {
this.loading = true;
const { $axios } = this;
/*const previewResponse = await $axios.$get(preview(this.mailingId), {
responseType: 'arraybuffer',
});
this.previewImage = Buffer.from(previewResponse, 'binary').toString(
'base64'
);*/
console.log({mailing: this.mailing})
this.loading = false;
} catch (error) {
this.errorPreview = true;
}
this.loading = true;
},
methods: {
onImageLoad() {
this.loading = false
}
}
};
</script>
<template>
Expand All @@ -41,15 +34,16 @@ export default {
</div>
<div class="max_height_img_container">
<v-skeleton-loader
:loading="loading"
v-show="loading"
class="preview_container"
type="image, image">
<img
class="max_width_img"
:src="`data:image/png;base64,${previewImage}`"
:alt="$t('global.previewMailAlt')"
/>
</v-skeleton-loader>
type="image, image"
/>
<v-img
class="max_width_img"
@load="onImageLoad"
:src="images(this.mailing.previewFileUrl)"
:alt="$t('global.previewMailAlt')"
/>
</div>
</div>
</template>
Expand Down

0 comments on commit f294ee3

Please sign in to comment.