Skip to content

Commit

Permalink
Nuevo mail de proyecto publicado/published a usuarios con tags/etique…
Browse files Browse the repository at this point in the history
…tas similares
  • Loading branch information
franz committed Sep 22, 2020
1 parent 26c8b90 commit fa3ce8b
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 1 deletion.
138 changes: 138 additions & 0 deletions api/controllers/document-published.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
const { INTERNAL_SERVER_ERROR, OK } = require('http-status')
const { ObjectID } = require('mongodb')
const mongo = require('../../services/db')
const notification = require('../../core/notification-strategies')

function log(msg){
console.log('api/controllers/document-published.js:', msg)
}

exports.post = async (req, res) => {
try {
const { documentId } = req.body

const db = mongo.getDB()

// Traemos datos del proyecto, su versión actual y su autor/a
const documentsArr = await db.collection('documents').aggregate([
{ $match: { _id: ObjectID(documentId) } },
{
$lookup: {
from: 'documentversions',
localField: 'currentVersion',
foreignField: '_id',
as: 'currentVersionObj'
}
},
{ $unwind : "$currentVersionObj" },
{
$lookup: {
from: 'users',
localField: 'author',
foreignField: '_id',
as: 'authorObj'
}
},
{ $unwind : "$authorObj" }
]).toArray()

// Muchas validaciones antes de preparar la enviada de mails
if (!documentsArr || !documentsArr.length)
throw new Error(`Document ${documentId} not found`)

const documentObj = documentsArr[0]

if (documentObj.publishedMailSent)
throw new Error(`Already sent published mail for document ${documentId}`)

const currentVersionObj = documentObj.currentVersionObj

if (!currentVersionObj)
throw new Error(`DocumentVersion ${documentObj.currentVersion} not found`)

const tagsIds = currentVersionObj.content.tags
log(`Preparing notification for "${currentVersionObj.content.title}"`)

if (!tagsIds || !tagsIds.length){
log('No tags found for document, skipping notification')
res.status(OK).json({
message: 'No tags found for document, skipping notification'
})
return
}

// Buscamos toda la información de las etiquetas
const tagsData = await db.collection('documenttags')
.find({ _id: { $in: tagsIds.map(id => ObjectID(id)) } })
.toArray()
log(`Document has ${tagsData.length} tags: "${tagsData.map(t=>t.name).join('", "')}"`)

// Buscamos todxs lxs usuarixs suscriptos a 1 o más de las etiquetas
const users = await db.collection('users')
.find({$and: [
{allowTagsMail: true},
{'fields.tags': {$in: tagsIds}}
]}).toArray()
log(`Found ${users.length} subscribed users (to all or some of document's tags)`)

if (!users || !users.length){
log('No users found for document\'s tags, skipping notification')
res.status(OK).json({
message: 'No users found for document\'s tags, skipping notification'
})
return
}

// Rutina de mandada de mails (secuencial)
let emailsSent = 0

users.forEach(user => {

const userEmail = user && user.email

try {

if (!userEmail){
log(`User "${user.username}" has no email, skipping notification for her/him`)
return
}

const matchingTags = tagsData.filter(t => user.fields.tags.includes(t._id.toString())).map(t => t.name)

notification.sendEmail('document-published', {
user: {
email: userEmail,
name: user.name || user.username
},
document: {
id: documentObj._id,
title: currentVersionObj.content.title,
author: documentObj.authorObj.fullname || documentObj.authorObj.username
},
matchingTags: matchingTags
})

emailsSent++

} catch (err) {

log(`Error when sending mail to ${userEmail}:`)
log(err)

}
})

// Devolvemos OK
log(`${emailsSent} email(s) scheduled`)
res.status(OK).json({
message: `${emailsSent} email(s) scheduled`
});

} catch (err) {
log(err)
res.status(INTERNAL_SERVER_ERROR).json({
message: 'An error ocurred trying to schedule the email.',
reason: err.message
})
}
}
7 changes: 7 additions & 0 deletions api/routes/document-published.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const express = require('express')
const router = express.Router()
const DocumentPublished = require('../controllers/document-published')

router.post('/', DocumentPublished.post)

module.exports = router
2 changes: 2 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require('dotenv').config()
const sendEmailRoutes = require('./api/routes/send-email')
const setCloseEvent = require('./api/routes/document-closes')
const setNewCommentEvent = require('./api/routes/comment-new')
const documentPublishedRoutes = require('./api/routes/document-published')

const { NODE_ENV } = process.env

Expand All @@ -29,6 +30,7 @@ app.use((req, res, next) => {
app.use('/api/send-email', sendEmailRoutes)
app.use('/api/set-document-closes', setCloseEvent)
app.use('/api/comment-new', setNewCommentEvent)
app.use('/api/document-published', documentPublishedRoutes)

if (NODE_ENV === 'development') app.use('/views', require('./api/routes/dev-view'))

Expand Down
8 changes: 7 additions & 1 deletion core/notification-strategies.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,18 @@ const commentContribution = (info) => {
execute(info.author.email, '¡Comentario marcado como aporte!', template)
}

const documentPublished = (info) => {
const template = buildTemplate('document-published', info)
execute(info.user.email, '¡Proyecto publicado!', template)
}

const strategies = [
['comment-new', commentNew],
['comment-resolved', commentResolved],
['comment-liked', commentLiked],
['comment-replied', commentReplied],
['comment-contribution', commentContribution]
['comment-contribution', commentContribution],
['document-published', documentPublished]
]

const strategiesMap = new Map(strategies)
Expand Down
46 changes: 46 additions & 0 deletions templates/document-published.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const React = require('react')
const { Email, Item, Span, A, renderEmail, Box, Image } = require('react-html-email')
const MailHeader = require('./header')
const MailFooter = require('./footer')
const Content = require('./content')
const Style = require('./styles')
const CommentContainerStyle = require('./commentContainerStyle')
const { ORGANIZATION_NAME, ORGANIZATION_URL, ORGANIZATION_API_URL } = process.env

const DocumentPublished = (props) => {
return (
<Email title='Proyecto publicado' style={{ width: '100%', maxWidth: '700px' }}>
<MailHeader />
<Content name={props.user.name} style={{ width: '100%' }}>

<Item style={Style.itemStyle}>
<Span {...Style.defaultContentStyle}>
Se ha publicado el proyecto <b>{props.document.title}</b> de <b>{props.document.author}</b> en el <A href={`${ORGANIZATION_URL}/propuesta?id=${props.document.id}`}>{ORGANIZATION_NAME}</A>.
</Span>
</Item>

<Item style={Style.itemStyle}>
<Span {...Style.defaultContentStyle}>
Usted está recibiendo esta notificación ya que el proyecto tiene las siguientes etiquetas de su interés:
<br />
"{props.matchingTags.join('", "')}"
</Span>
</Item>

<Item style={Style.itemStyle}><br /></Item>

<Item style={Style.itemStyle}>
<em>
<Span {...Style.defaultContentStyle}>
Si desea desactivar estas notificaciones o cambiar sus etiquetas de interés puede ir a <A href={`${ORGANIZATION_URL}/userprofile`}>Editar perfil</A>.
</Span>
</em>
</Item>

</Content>
<MailFooter />
</Email>
)
}

module.exports = (props) => renderEmail(<DocumentPublished {...props} />)

0 comments on commit fa3ce8b

Please sign in to comment.