Skip to content

Commit

Permalink
Feat/emails (#97)
Browse files Browse the repository at this point in the history
* Emails for campaigns

* Save new email templates json export

* Preselection flow and email

* Fixes and campaign update before lifecycle

* Cron schedule

* Email exports
  • Loading branch information
Lucieo authored Mar 1, 2024
1 parent db0dad5 commit ae499fa
Show file tree
Hide file tree
Showing 29 changed files with 810 additions and 107 deletions.
5 changes: 5 additions & 0 deletions back/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"trailingComma": "all"
}
3 changes: 3 additions & 0 deletions back/api/application/documentation/1.0.0/application.json
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,9 @@
"preselections_max": {
"type": "integer"
},
"is_active": {
"type": "boolean"
},
"published_at": {
"type": "string"
},
Expand Down
154 changes: 152 additions & 2 deletions back/api/application/models/application.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,158 @@
'use strict';
'use strict'
const format = require('date-fns/format')
const fr = require('date-fns/locale/fr')

const locale = {
locale: fr,
}

/**
* Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#lifecycle-hooks)
* to customize this model
*/

module.exports = {};
module.exports = {
lifecycles: {
async afterCreate(created) {
try {
const applicationsCount = await strapi.services.application.count({
company: created.company.id,
campaign: created.disponibility.campaign,
})
const campaign = await strapi.services.campaign.findOne({
id: created.disponibility.campaign,
})
const nb_applications = campaign.applications_max - applicationsCount

const lieu = await strapi.plugins[
'users-permissions'
].services.user.fetch({
id: created.espace.users_permissions_user,
})

// // Send email to the company
strapi.plugins['email'].services.email.sendEmail(
{
to: created.company.email,
},
{
templateId: 'compagny-application-confirm',
subject: `Votre candidature a bien été prise en compte`,
},
{
lieu_name: lieu.structureName,
espace_name: created.espace.name,
date_start: format(
new Date(created.disponibility.start),
'dd/MM',
locale,
),
date_end: format(
new Date(created.disponibility.end),
'dd/MM',
locale,
),
user_name: created.company.firstname,
applications_end_date: format(
new Date(campaign.application_end),
'dd MMMM yyyy',
locale,
),
nb_applications,
},
)

// // Send email to the place
strapi.plugins['email'].services.email.sendEmail(
{
to: lieu.email,
},
{
templateId: 'place-application-confirm',
subject: `Une candidature vient d'être déposée`,
},
{
user_name: lieu.firstname,
company_name: created.company.structureName,
espace_name: created.espace.name,
date_start: format(
new Date(created.disponibility.start),
'dd/MM',
locale,
),
date_end: format(
new Date(created.disponibility.end),
'dd/MM',
locale,
),
},
)
} catch (e) {
console.log('error', e)
}
},
async afterDelete(deleted) {
try {
const lieu = await strapi.plugins[
'users-permissions'
].services.user.fetch({
id: deleted.espace.users_permissions_user,
})

// // Send email to the company
strapi.plugins['email'].services.email.sendEmail(
{
to: deleted.company.email,
},
{
templateId: 'compagny-application-cancel',
subject: `L'annulation de votre candidature a bien été prise en compte`,
},
{
lieu_name: lieu.structureName,
espace_name: deleted.espace.name,
date_start: format(
new Date(deleted.disponibility.start),
'dd/MM',
locale,
),
date_end: format(
new Date(deleted.disponibility.end),
'dd/MM',
locale,
),
user_name: deleted.company.firstname,
},
)

// // Send email to the place
strapi.plugins['email'].services.email.sendEmail(
{
to: lieu.email,
},
{
templateId: 'place-application-cancel',
subject: `Une candidature vient d'être annulée`,
},
{
user_name: lieu.firstname,
company_name: deleted.company.structureName,
espace_name: deleted.espace.name,
date_start: format(
new Date(deleted.disponibility.start),
'dd/MM',
locale,
),
date_end: format(
new Date(deleted.disponibility.end),
'dd/MM',
locale,
),
},
)
} catch (e) {
console.log('error', e)
}
},
},
}
6 changes: 6 additions & 0 deletions back/api/campaign/documentation/1.0.0/campaign.json
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,9 @@
"preselections_max": {
"type": "integer"
},
"is_active": {
"type": "boolean"
},
"published_at": {
"type": "string",
"format": "date-time"
Expand Down Expand Up @@ -1016,6 +1019,9 @@
"preselections_max": {
"type": "integer"
},
"is_active": {
"type": "boolean"
},
"published_at": {
"type": "string",
"format": "date-time"
Expand Down
17 changes: 15 additions & 2 deletions back/api/campaign/models/campaign.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
'use strict';
'use strict'

/**
* Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#lifecycle-hooks)
* to customize this model
*/

module.exports = {};
module.exports = {
lifecycles: {
beforeUpdate: async (params, data) => {
// Campaign has a relationship with applications and disponibilities but shouldn't update those to avoid data loss on admin update
const currentCampaignState = await strapi.services.campaign.findOne(
params,
)
if (currentCampaignState) {
data.applications = currentCampaignState.applications
data.disponibilities = currentCampaignState.disponibilities
}
},
},
}
3 changes: 3 additions & 0 deletions back/api/campaign/models/campaign.settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@
},
"preselections_max": {
"type": "integer"
},
"is_active": {
"type": "boolean"
}
}
}
122 changes: 120 additions & 2 deletions back/api/campaign/services/campaign.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,126 @@
'use strict';
'use strict'
const format = require('date-fns/format')
const fr = require('date-fns/locale/fr')

const locale = {
locale: fr,
}

/**
* Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#core-services)
* to customize this service
*/

module.exports = {};
module.exports = {
async sendApplicationEndEmail(campaign, place) {
// // Send email to the place when application time is over
await strapi.plugins['email'].services.email.sendEmail(
{
to: place.email,
},
{
templateId: 'place-application-end',
subject: `La période de candidature est terminée`,
},
{
date_end: format(
new Date(campaign.preselection_end),
'dd/MM/yyyy',
locale,
),
url_btn: `${process.env.FRONT_URL}/compte/candidatures?campaign=${campaign.id}`,
},
)
},
async sendPreselectionReminder(campaign, place) {
// // Send reminder to the place when preselection time is nearly over AND place has missing selections
const place_missing_selections =
await strapi.services.campaign.getPlaceMissingSelections(place, campaign)

if (place_missing_selections && place_missing_selections?.length > 0) {
await strapi.plugins['email'].services.email.sendEmail(
{
to: place.email,
},
{
templateId: 'place-preselections-reminder',
subject: `Il vous reste ${campaign?.reminder_days} ${
campaign?.reminder_days > 1 ? 'jours' : 'jour'
} pour compléter votre pré-sélection`,
},
{
missing_selections: place_missing_selections,
reminder_days: `${campaign?.reminder_days} ${
campaign?.reminder_days > 1 ? 'jours' : 'jour'
}`,
url_btn: `${process.env.FRONT_URL}/compte/candidatures?campaign=${campaign.id}`,
},
)
}
},
async sendPreselectionsEnd(campaign, place) {
// Send reminder to the place when preselection time is over AND place has missing selections
const place_missing_selections =
await strapi.services.campaign.getPlaceMissingSelections(place, campaign)

if (place_missing_selections) {
if (place_missing_selections?.length > 0) {
await strapi.plugins['email'].services.email.sendEmail(
{
to: place.email,
},
{
templateId: 'place-preselections-end',
subject: `La date limite de pré-sélection a été atteinte`,
},
{
missing_selections: place_missing_selections,
},
)
} else {
await strapi.plugins['email'].services.email.sendEmail(
{
to: place.email,
},
{
templateId: 'place-preselections-end-ok',
subject: `La période de candidature est terminée`,
},
{
missing_selections: place_missing_selections,
},
)
}
}
},
async getPlaceMissingSelections(place, campaign) {
const place_campaign_disponibilities =
await strapi.services.disponibility.find(
{
'espace.users_permissions_user': place.id,
'espace.published': true,
campaign: campaign.id,
},
['applications', 'espace'],
)
// If place is campaign participan but has 0 disponibilities don't include it in mailing campaigin
if (!place_campaign_disponibilities?.length) return null

const place_missing_selections = place_campaign_disponibilities
.filter(
(d) =>
d?.applications?.length &&
!d?.applications?.some((a) => a.status === 'confirmed'),
)
.map((disponibility) => ({
espace_name: disponibility?.espace?.name,
date_start: format(
new Date(disponibility?.start),
'dd/MM/yyyy',
locale,
),
date_end: format(new Date(disponibility?.end), 'dd/MM/yyyy', locale),
}))
return place_missing_selections
},
}
8 changes: 8 additions & 0 deletions back/api/disponibility/config/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@
"config": {
"policies": ["global::is-place", "is-owner"]
}
},
{
"method": "POST",
"path": "/disponibilities/:id/campaign/:campaignId/confirm",
"handler": "disponibility.campaignConfirm",
"config": {
"policies": ["global::is-place", "is-owner"]
}
}
]
}
Loading

0 comments on commit ae499fa

Please sign in to comment.