This commit is contained in:
root 2020-07-21 14:41:07 +00:00
parent 0c881c919b
commit 4a97c240eb
16 changed files with 217 additions and 59 deletions

View file

@ -25,7 +25,7 @@ export default class EmailService {
pass: process.env.SMTP_PASSWORD, pass: process.env.SMTP_PASSWORD,
} }
} }
console.log(config) //console.log(config)
return nodemailer.createTransport(config) return nodemailer.createTransport(config)
} }
@ -73,7 +73,7 @@ export default class EmailService {
} else { } else {
this.nativeSend(config).then(res => { this.nativeSend(config).then(res => {
console.log('> A "' + templateName + '" email was sent') console.log('> A "' + templateName + '" email was sent')
resolve() resolve(res)
}).catch(err => { }).catch(err => {
console.log('> A "' + templateName + '" email failed to be sent') console.log('> A "' + templateName + '" email failed to be sent')
console.error(err) console.error(err)

View file

@ -19,6 +19,8 @@ export default class AdminOrganizationController {
} }
static import(req: express.Request, res: express.Response) { static import(req: express.Request, res: express.Response) {
// first column is always name
// second column is always email
const data = req.body.csv const data = req.body.csv
res.json({ res.json({
success: true, success: true,
@ -69,8 +71,8 @@ export default class AdminOrganizationController {
.then(data => { .then(data => {
// generate extra slugs // generate extra slugs
let extra: any = {} let extra: any = {}
if (req.body.name !== undefined) { if (req.body.adminName !== undefined) {
let slug = slugify(req.body.name) let slug = slugify(req.body.adminName)
// only add this slug if the proposed slug is not found in the list of current slug // only add this slug if the proposed slug is not found in the list of current slug
let currentSlugs: string[] = [] let currentSlugs: string[] = []
if (data !== null && Array.isArray(data.get('slugs'))) { if (data !== null && Array.isArray(data.get('slugs'))) {
@ -164,6 +166,22 @@ export default class AdminOrganizationController {
const publishedVersion: any = data.get('publishedVersion') const publishedVersion: any = data.get('publishedVersion')
const proposedVersion: any = data.get('proposedVersion') const proposedVersion: any = data.get('proposedVersion')
// generate extra slugs
// in case of a change by the organization it self, we need to keep up to date the slug
let extra: any = {}
let slug = slugify(proposedVersion.name)
// only add this slug if the proposed slug is not found in the list of current slug
let currentSlugs: string[] = []
if (Array.isArray(data.get('slugs'))) {
currentSlugs = data.get('slugs')
}
if (currentSlugs.filter(s => s === slug).length === 0) {
extra.slugs = currentSlugs.concat([slug])
}
extra.adminName = proposedVersion.name
extra.email = proposedVersion.contacts.email
/** /**
* Clean all the unused media from the publishedVersion * Clean all the unused media from the publishedVersion
*/ */
@ -203,6 +221,7 @@ export default class AdminOrganizationController {
*/ */
Organization.updateOne({ _id: req.params.id }, { Organization.updateOne({ _id: req.params.id }, {
...extra,
publishedVersion: data.get('proposedVersion'), publishedVersion: data.get('proposedVersion'),
rejectionDescription: '', rejectionDescription: '',
validationState: 'published', validationState: 'published',

View file

@ -59,15 +59,17 @@ export default class DefaultController {
static async sendEmail(req: express.Request, res: express.Response) { static async sendEmail(req: express.Request, res: express.Response) {
// create reusable transporter object using the default SMTP transport // create reusable transporter object using the default SMTP transport
EmailService.getTransporter().sendMail({ EmailService.send(
from: '"Some Sender" <noreply@somedomain.com>', 'matthieu.bessat.27@gmail.com',
to: "spamfree@matthieubessat.fr", "Email de test",
subject: "Hello ✔", "token",
text: "Hello world? Comment va tu Earum facilis libero excepturi sunt fuga eveniet autem. Illo odit quae aperiam et praesentium. Error dignissimos atque omnis. Ea iste in doloribus praesentium corrupti. Ut consequatur eius eveniet quia aut. Nam a rerum quis. Repudiandae sit nobis esse. Eaque ipsum qui enim. Expedita laudantium officia omnis maxime. Odio exercitationem recusandae quis consequatur voluptatum.", {
html: "<p><b>Hello world?</b> Comment va tu Earum facilis libero excepturi sunt fuga eveniet autem. Illo odit quae aperiam et praesentium. Error dignissimos atque omnis. Ea iste in doloribus praesentium corrupti. Ut consequatur eius eveniet quia aut. Nam a rerum quis. Repudiandae sit nobis esse. Eaque ipsum qui enim. Expedita laudantium officia omnis maxime. Odio exercitationem recusandae quis consequatur voluptatum.</p>", adminName: "Assos de test",
}).then(info => { token: "tokendetest",
console.log("Message sent: %s", info.messageId); link: EmailService.getWebUiBaseUrl() + '/delegate?delegateToken=tokendetest'
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info)); }
).then(info => {
console.log(info)
}).catch(err => { }).catch(err => {
console.error(err) console.error(err)
}) })

View file

@ -22,6 +22,7 @@ export default class PublicController {
// }) // })
Tag.find().then(tags => { Tag.find().then(tags => {
let isProposed = Utils.isStrUsable(req.query, 'only') let isProposed = Utils.isStrUsable(req.query, 'only')
// @ts-ignore
if (isProposed && !mongoose.Types.ObjectId.isValid(req.query.only)) { if (isProposed && !mongoose.Types.ObjectId.isValid(req.query.only)) {
return ErrorController.handleServerError({ stack: 'Invalid object id in only query param'}, req, res, []) return ErrorController.handleServerError({ stack: 'Invalid object id in only query param'}, req, res, [])
} }
@ -105,10 +106,19 @@ export default class PublicController {
return media return media
}) })
} }
version.cutDescription = Utils.isStrUsable(version, 'descriptionLong') && version.descriptionLong.length > 200
// if (version.cutDescription) {
// version.descriptionFirstHalf = version.descriptionLong.substr(0, 200) // not gonna lie
// version.descriptionSecondHalf = version.descriptionLong.substr(200)
// }
let hour = lastPublished.toLocaleTimeString('fr-FR', { timezone: '+2' })
if (hour.charAt(1) === ':') {
hour = '0' + hour
}
res.render('organization.twig', { res.render('organization.twig', {
layout: 'standalone', layout: 'standalone',
data: version, data: version,
lastPublished: lastPublished.toLocaleDateString('fr-FR') + ' ' + lastPublished.toLocaleTimeString('fr-FR', { timezone: '+2' }).substr(0, 5), lastPublished: lastPublished.toLocaleDateString('fr-FR') + ' ' + hour.substr(0, 5),
isProposed, isProposed,
id: org.get('_id') id: org.get('_id')
}) })

View file

@ -58,7 +58,13 @@ const OrganizationVersion = {
address: { type: String }, address: { type: String },
person: { type: String }, person: { type: String },
email: { type: String }, email: { type: String },
phone: { type: String } phone: { type: String },
peoples: [{
name: { type: String },
email: { type: String },
phone: { type: String },
role: { type: String }
}]
}, },
schedule: [{ schedule: [{
name: { type: String, required: true }, name: { type: String, required: true },

View file

@ -181,15 +181,16 @@
margin-bottom: 1em; margin-bottom: 1em;
box-shadow: 0 0 8px 0px rgba(0,0,0,0.1); box-shadow: 0 0 8px 0px rgba(0,0,0,0.1);
transition: all 0.2s; transition: all 0.2s;
height: 12em;
overflow: hidden; overflow: hidden;
text-decoration: none;
} }
.card:hover { .card:hover {
text-decoration: none;
transform: scale(1.02); transform: scale(1.02);
} }
.card-image { .card-image-container {
border-right: 1px solid #C4C4C4; border-right: 1px solid #C4C4C4;
display: flex; display: flex;
@ -199,8 +200,12 @@
padding: 1em; padding: 1em;
} }
.card-image img { .card-image {
height: 12em;
width: 12em; width: 12em;
background-position: center;
background-size: cover;
} }
.card-content { .card-content {
@ -332,9 +337,13 @@
.card { .card {
display: block; display: block;
} }
.card-image { .card-image-container {
padding: 0;
margin: 0;
border-right: 0; border-right: 0;
border-bottom: 1px solid #C4C4C4; border-bottom: 1px solid #C4C4C4;
margin: 0; }
.card-content {
width: auto;
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -15,12 +15,12 @@ navEnabler.onclick = async () => {
// open the menu // open the menu
oldNavText = navEnablerText.textContent oldNavText = navEnablerText.textContent
navEnablerText.textContent = "Minimiser le menu" navEnablerText.textContent = "Minimiser le menu"
navEnablerIcon.style.transform = "rotate(0deg)" navEnablerIcon.style.transform = "rotate(90eg)"
navContent.style.maxHeight = navContent.scrollHeight + "px" navContent.style.maxHeight = navContent.scrollHeight + "px"
} else { } else {
// close the menu // close the menu
navEnablerText.textContent = oldNavText navEnablerText.textContent = oldNavText
navEnablerIcon.style.transform = "rotate(-90deg)" navEnablerIcon.style.transform = "rotate(0deg)"
navContent.style.maxHeight = null navContent.style.maxHeight = null
} }
navOpened = !navOpened navOpened = !navOpened
@ -82,12 +82,12 @@ function setAttributes(node, attrs) {
} }
function renderCard(organization) { function renderCard(organization) {
let card = createEl('card') let card = createEl('card', 'a')
// image // image
let image = createEl('card-image') let image = createEl('card-image-container')
let imageTag = createEl(0, 'img') let imageTag = createEl('card-image')
imageTag.src = organization.thumbnail imageTag.style = `background-image: url('${organization.thumbnail}')`
image.appendChild(imageTag) image.appendChild(imageTag)
card.appendChild(image) card.appendChild(image)
@ -117,14 +117,15 @@ function renderCard(organization) {
let description = createEl('card-description') let description = createEl('card-description')
description.textContent = organization.description description.textContent = organization.description
//let link = createEl('card-link') let goTo = "/association/" + organization.slugs[organization.slugs.length - 1]
let aTag = createEl('card-link', 'a')
aTag.href = "/association/" + organization.slugs[organization.slugs.length - 1]
if (organization.isProposed) { if (organization.isProposed) {
aTag.href += "?version=proposed" goTo += "?version=proposed"
} }
aTag.textContent = "En savoir plus" // let link = createEl('card-link')
description.appendChild(aTag) // let aTag = createEl('card-link', 'a')
// aTag.href =
// aTag.textContent = "En savoir plus"
// description.appendChild(aTag)
upperContent.appendChild(description) upperContent.appendChild(description)
//link.appendChild(aTag) //link.appendChild(aTag)
@ -132,9 +133,11 @@ function renderCard(organization) {
//content.appendChild(link) //content.appendChild(link)
card.appendChild(content) card.appendChild(content)
card.onclick = () => { card.href = goTo
window.location = aTag.href
} // card.onclick = () => {
// window.location = goTo
// }
return card return card
} }

View file

@ -9,17 +9,43 @@ document.querySelectorAll('.schedule-category').forEach(node => {
header.onclick = () => { header.onclick = () => {
if (!opened) { if (!opened) {
// open the table // open the table
icon.style.transform = "rotate(180deg)" icon.style.transform = "rotate(0deg)"
content.style.maxHeight = content.scrollHeight + "px" content.style.maxHeight = content.scrollHeight + "px"
} else { } else {
// close the table // close the table
icon.style.transform = "rotate(0deg)" icon.style.transform = "rotate(180deg)"
content.style.maxHeight = null content.style.maxHeight = null
} }
opened = !opened opened = !opened
} }
}) })
/**
* Description
*/
let description = document.querySelector('.description-cutted')
let descriptionActions = document.querySelector('.description-actions-container')
let descriptionOpened = false
let defaultMaxHeight = ""
if (description !== null) {
let btn = document.querySelector('.description-btn')
btn.onclick = () => {
if (!descriptionOpened) {
// open the full description
descriptionActions.className = descriptionActions.className.replace(' closed', '')
defaultMaxHeight = description.style.maxHeight
description.style.maxHeight = description.scrollHeight + "px"
btn.textContent = "Fermer la description"
} else {
// initial max Height
descriptionActions.className += ' closed'
description.style.maxHeight = defaultMaxHeight
btn.textContent = "Ouvrir la description"
}
descriptionOpened = !descriptionOpened
}
}
/** /**
* Gallery modal to view media in large * Gallery modal to view media in large
*/ */
@ -70,8 +96,22 @@ let openModal = (url, isVideo) => {
//document.body.style.height = '100vh' //document.body.style.height = '100vh'
document.body.style.overflow = 'hidden' document.body.style.overflow = 'hidden'
document.body.style.touchAction = 'none' document.body.style.touchAction = 'none'
setTimeout(() => {
const outsideClickListener = event => {
if (!mediaModalContent.contains(event.target) && isVisible(mediaModalContent)) {
closeModal()
document.removeEventListener('click', outsideClickListener)
}
}
document.addEventListener('click', outsideClickListener)
}, 100)
} }
const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length )
let closeModal = () => { let closeModal = () => {
mediaModal.style.visibility = 'hidden' mediaModal.style.visibility = 'hidden'
mediaModal.style.opacity = 0 mediaModal.style.opacity = 0

View file

@ -53,6 +53,19 @@ body {
color: white; color: white;
} }
.btn {
padding: .5em 1em;
color: white;
border-radius: 7px;
background: #2c3e50;
border: 0;
}
.btn:focus {
outline: 0;
opacity: 0.8;
}
@media (max-width: 1600px) { @media (max-width: 1600px) {
.container { .container {
width: 70%; width: 70%;

View file

@ -57,7 +57,7 @@
.cover { .cover {
height: 13em; height: 13em;
margin-top: -13em; margin-top: -13em;
background-color: rgba(230, 126, 34, 0.78); background-color: rgba(230, 126, 34, 0.4);
background-size: cover; background-size: cover;
} }
@ -294,7 +294,7 @@ section {
text-align: justify; text-align: justify;
margin: 0 auto; margin: 0 auto;
width: 80%; width: 80%;
margin-top: 1.5em; margin-top: 1em;
margin-bottom: .5em; margin-bottom: .5em;
} }
@ -332,16 +332,37 @@ section {
padding-left: 1em; padding-left: 1em;
} }
.description-cutted {
max-height: 13em;
overflow: hidden;
transition: max-height 0.1s ease-out;
}
.description-actions-container {
display: flex;
justify-content: center;
align-items: center;
margin-top: 1em;
}
.description-actions-container.closed {
box-shadow: 0px -16px 16px -3px rgb(255, 255, 255);
background: rgba(255,255,255,0.8);
position: relative;
top: -62px;
height: 62px;
margin-bottom: -62px;
}
/* ***************************************************************************** /* *****************************************************************************
* SCHEDULE * SCHEDULE
********************************************************************************/ ********************************************************************************/
.schedule {
}
.schedule-category { .schedule-category {
margin-bottom: 1em; margin-bottom: 1em;
} }
@ -357,13 +378,13 @@ section {
} }
.schedule-category-collapse-icon { .schedule-category-collapse-icon {
transform: rotate(180deg);
color: #B12008; color: #B12008;
width: 1.5em; width: 1.5em;
transition: all 0.1s ease-out; transition: all 0.1s ease-out;
} }
.schedule-category-table { .schedule-category-table {
max-height: 0; max-height: 0;
overflow: hidden; overflow: hidden;
transition: max-height 0.1s ease-out; transition: max-height 0.1s ease-out;
@ -376,7 +397,7 @@ section {
margin-left: 2em; margin-left: 2em;
margin-top: 1em; margin-top: 1em;
margin-bottom: 1em; margin-bottom: 1em;
margin-right: 40em; margin-right: 20em;
padding: 1em 2em 1em 2em; padding: 1em 2em 1em 2em;
} }
@ -395,6 +416,14 @@ section {
margin-bottom: 0; margin-bottom: 0;
} }
.schedule-category-hours {
color: #2c3e50;
}
.schedule-category-hours .spearator {
color: #bdc3c7;
}
/* ***************************************************************************** /* *****************************************************************************
* PRICING * PRICING
@ -450,7 +479,7 @@ section {
********************************************************************************/ ********************************************************************************/
.contact { .org-container {
margin: 0 auto; margin: 0 auto;
width: 70%; width: 70%;
} }
@ -541,13 +570,15 @@ section {
.mentions { .mentions {
display: flex; display: flex;
justify-content: center; justify-content: center;
width: 100%; padding-left: 1em;
padding-right: 1em;
flex-direction: column; flex-direction: column;
text-align: center; text-align: center;
color: #d35400; color: #d35400;
margin-top: 2em; margin-top: 1em;
margin-bottom: .5em; margin-bottom: 1em;
} }
.mentions div { .mentions div {
margin-bottom: .5em; margin-bottom: .5em;
} }
@ -589,17 +620,17 @@ RESPONSIVE
@media (max-width: 900px) { @media (max-width: 900px) {
.cover-background { .cover-background {
height: 30em; height: 23em;
width: 100%; width: 100%;
} }
.cover { .cover {
height: 30em; height: 23em;
margin-top: -30em; margin-top: -23em;
} }
.cover-content { .cover-content {
height: 30em; height: 23em;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@ -628,6 +659,10 @@ RESPONSIVE
} }
/* Mosaic level 2 */ /* Mosaic level 2 */
.mosaic-2 {
grid-template-rows: 1fr 1fr;
}
.mosaic-2, .mosaic-3 { .mosaic-2, .mosaic-3 {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
@ -684,7 +719,7 @@ RESPONSIVE
margin-bottom: 1em; margin-bottom: 1em;
} }
.contact { .org-container {
width: 100%; width: 100%;
} }
@ -720,4 +755,7 @@ RESPONSIVE
.media-modal { .media-modal {
width: 90%; width: 90%;
} }
.description {
width: 95%;
}
} }

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View file

@ -35,7 +35,7 @@ Github: https://github.com/lefuturiste
class="header-sub-title"> class="header-sub-title">
Espace Condorcet Centre Social Espace Condorcet Centre Social
</a> </a>
<h1 class="header-title">Forum des associations</h1> <h1 class="header-title">Forum des associations 2020</h1>
<div class="header-description"> <div class="header-description">
Cette année nous vous invitons à découvrir le forum virtuel des associations. Cette année nous vous invitons à découvrir le forum virtuel des associations.
</div> </div>

7
views/emails/test.twig Normal file
View file

@ -0,0 +1,7 @@
<p>
This is a test
</p>
<p>
Date: {{ date }}
</p>

View file

@ -73,8 +73,17 @@
<div class="section-divider"></div> <div class="section-divider"></div>
</div> </div>
<div class="description"> <div class="description">
{% if data.descriptionLong is not null and data.descriptionLong|length > 7 %} {% if data.descriptionLong is not null and data.descriptionLong|length > 7 and not data.cutDescription %}
{{ data.descriptionLong|raw }} {{ data.descriptionLong|raw }}
{% elseif data.cutDescription %}
<div class="description-cutted">
{{ data.descriptionLong }}
</div>
<div class="description-actions-container closed">
<button class="btn description-btn">
Ouvrir la description
</button>
</div>
{% else %} {% else %}
{{ data.descriptionShort }} {{ data.descriptionShort }}
{% endif %} {% endif %}
@ -88,8 +97,9 @@
<h2>Crénaux</h2> <h2>Crénaux</h2>
<div class="section-divider"></div> <div class="section-divider"></div>
</div> </div>
<div class="schedule"> <div class="schedule org-container">
{% for item in data.schedule %} {% for item in data.schedule %}
{% if item.when|length > 0 %}
<div class="schedule-category"> <div class="schedule-category">
<div class="schedule-category-header" title="Déroulez"> <div class="schedule-category-header" title="Déroulez">
<div class="schedule-category-name"> <div class="schedule-category-name">
@ -120,6 +130,7 @@
</div> </div>
</div> </div>
</div> </div>
{% endif %}
{% endfor %} {% endfor %}
</div> </div>
</section> </section>
@ -155,7 +166,7 @@
<h2>Contact</h2> <h2>Contact</h2>
<div class="section-divider"></div> <div class="section-divider"></div>
</div> </div>
<div class="contact"> <div class="org-container contact">
{% if data.contacts.person|length > 0 %} {% if data.contacts.person|length > 0 %}
<div class="contact-item person"> <div class="contact-item person">
<div class="contact-icon"> <div class="contact-icon">