update
This commit is contained in:
parent
0c881c919b
commit
4a97c240eb
16 changed files with 217 additions and 59 deletions
|
@ -25,7 +25,7 @@ export default class EmailService {
|
|||
pass: process.env.SMTP_PASSWORD,
|
||||
}
|
||||
}
|
||||
console.log(config)
|
||||
//console.log(config)
|
||||
return nodemailer.createTransport(config)
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ export default class EmailService {
|
|||
} else {
|
||||
this.nativeSend(config).then(res => {
|
||||
console.log('> A "' + templateName + '" email was sent')
|
||||
resolve()
|
||||
resolve(res)
|
||||
}).catch(err => {
|
||||
console.log('> A "' + templateName + '" email failed to be sent')
|
||||
console.error(err)
|
||||
|
|
|
@ -19,6 +19,8 @@ export default class AdminOrganizationController {
|
|||
}
|
||||
|
||||
static import(req: express.Request, res: express.Response) {
|
||||
// first column is always name
|
||||
// second column is always email
|
||||
const data = req.body.csv
|
||||
res.json({
|
||||
success: true,
|
||||
|
@ -69,8 +71,8 @@ export default class AdminOrganizationController {
|
|||
.then(data => {
|
||||
// generate extra slugs
|
||||
let extra: any = {}
|
||||
if (req.body.name !== undefined) {
|
||||
let slug = slugify(req.body.name)
|
||||
if (req.body.adminName !== undefined) {
|
||||
let slug = slugify(req.body.adminName)
|
||||
// only add this slug if the proposed slug is not found in the list of current slug
|
||||
let currentSlugs: string[] = []
|
||||
if (data !== null && Array.isArray(data.get('slugs'))) {
|
||||
|
@ -164,6 +166,22 @@ export default class AdminOrganizationController {
|
|||
const publishedVersion: any = data.get('publishedVersion')
|
||||
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
|
||||
*/
|
||||
|
@ -203,6 +221,7 @@ export default class AdminOrganizationController {
|
|||
*/
|
||||
|
||||
Organization.updateOne({ _id: req.params.id }, {
|
||||
...extra,
|
||||
publishedVersion: data.get('proposedVersion'),
|
||||
rejectionDescription: '',
|
||||
validationState: 'published',
|
||||
|
|
|
@ -59,15 +59,17 @@ export default class DefaultController {
|
|||
|
||||
static async sendEmail(req: express.Request, res: express.Response) {
|
||||
// create reusable transporter object using the default SMTP transport
|
||||
EmailService.getTransporter().sendMail({
|
||||
from: '"Some Sender" <noreply@somedomain.com>',
|
||||
to: "spamfree@matthieubessat.fr",
|
||||
subject: "Hello ✔",
|
||||
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>",
|
||||
}).then(info => {
|
||||
console.log("Message sent: %s", info.messageId);
|
||||
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
|
||||
EmailService.send(
|
||||
'matthieu.bessat.27@gmail.com',
|
||||
"Email de test",
|
||||
"token",
|
||||
{
|
||||
adminName: "Assos de test",
|
||||
token: "tokendetest",
|
||||
link: EmailService.getWebUiBaseUrl() + '/delegate?delegateToken=tokendetest'
|
||||
}
|
||||
).then(info => {
|
||||
console.log(info)
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
|
|
|
@ -22,6 +22,7 @@ export default class PublicController {
|
|||
// })
|
||||
Tag.find().then(tags => {
|
||||
let isProposed = Utils.isStrUsable(req.query, 'only')
|
||||
// @ts-ignore
|
||||
if (isProposed && !mongoose.Types.ObjectId.isValid(req.query.only)) {
|
||||
return ErrorController.handleServerError({ stack: 'Invalid object id in only query param'}, req, res, [])
|
||||
}
|
||||
|
@ -105,10 +106,19 @@ export default class PublicController {
|
|||
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', {
|
||||
layout: 'standalone',
|
||||
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,
|
||||
id: org.get('_id')
|
||||
})
|
||||
|
|
|
@ -58,7 +58,13 @@ const OrganizationVersion = {
|
|||
address: { type: String },
|
||||
person: { 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: [{
|
||||
name: { type: String, required: true },
|
||||
|
|
|
@ -181,15 +181,16 @@
|
|||
margin-bottom: 1em;
|
||||
box-shadow: 0 0 8px 0px rgba(0,0,0,0.1);
|
||||
transition: all 0.2s;
|
||||
height: 12em;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
text-decoration: none;
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.card-image {
|
||||
.card-image-container {
|
||||
border-right: 1px solid #C4C4C4;
|
||||
|
||||
display: flex;
|
||||
|
@ -199,8 +200,12 @@
|
|||
padding: 1em;
|
||||
}
|
||||
|
||||
.card-image img {
|
||||
.card-image {
|
||||
height: 12em;
|
||||
width: 12em;
|
||||
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
|
@ -332,9 +337,13 @@
|
|||
.card {
|
||||
display: block;
|
||||
}
|
||||
.card-image {
|
||||
.card-image-container {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid #C4C4C4;
|
||||
margin: 0;
|
||||
}
|
||||
.card-content {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
|
BIN
static/assets/img/favicon-16x16.png
Executable file
BIN
static/assets/img/favicon-16x16.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
BIN
static/assets/img/favicon-32x32.png
Executable file
BIN
static/assets/img/favicon-32x32.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
|
@ -15,12 +15,12 @@ navEnabler.onclick = async () => {
|
|||
// open the menu
|
||||
oldNavText = navEnablerText.textContent
|
||||
navEnablerText.textContent = "Minimiser le menu"
|
||||
navEnablerIcon.style.transform = "rotate(0deg)"
|
||||
navEnablerIcon.style.transform = "rotate(90eg)"
|
||||
navContent.style.maxHeight = navContent.scrollHeight + "px"
|
||||
} else {
|
||||
// close the menu
|
||||
navEnablerText.textContent = oldNavText
|
||||
navEnablerIcon.style.transform = "rotate(-90deg)"
|
||||
navEnablerIcon.style.transform = "rotate(0deg)"
|
||||
navContent.style.maxHeight = null
|
||||
}
|
||||
navOpened = !navOpened
|
||||
|
@ -82,12 +82,12 @@ function setAttributes(node, attrs) {
|
|||
}
|
||||
|
||||
function renderCard(organization) {
|
||||
let card = createEl('card')
|
||||
let card = createEl('card', 'a')
|
||||
|
||||
// image
|
||||
let image = createEl('card-image')
|
||||
let imageTag = createEl(0, 'img')
|
||||
imageTag.src = organization.thumbnail
|
||||
let image = createEl('card-image-container')
|
||||
let imageTag = createEl('card-image')
|
||||
imageTag.style = `background-image: url('${organization.thumbnail}')`
|
||||
image.appendChild(imageTag)
|
||||
card.appendChild(image)
|
||||
|
||||
|
@ -117,14 +117,15 @@ function renderCard(organization) {
|
|||
let description = createEl('card-description')
|
||||
description.textContent = organization.description
|
||||
|
||||
//let link = createEl('card-link')
|
||||
let aTag = createEl('card-link', 'a')
|
||||
aTag.href = "/association/" + organization.slugs[organization.slugs.length - 1]
|
||||
let goTo = "/association/" + organization.slugs[organization.slugs.length - 1]
|
||||
if (organization.isProposed) {
|
||||
aTag.href += "?version=proposed"
|
||||
goTo += "?version=proposed"
|
||||
}
|
||||
aTag.textContent = "En savoir plus"
|
||||
description.appendChild(aTag)
|
||||
// let link = createEl('card-link')
|
||||
// let aTag = createEl('card-link', 'a')
|
||||
// aTag.href =
|
||||
// aTag.textContent = "En savoir plus"
|
||||
// description.appendChild(aTag)
|
||||
|
||||
upperContent.appendChild(description)
|
||||
//link.appendChild(aTag)
|
||||
|
@ -132,9 +133,11 @@ function renderCard(organization) {
|
|||
//content.appendChild(link)
|
||||
card.appendChild(content)
|
||||
|
||||
card.onclick = () => {
|
||||
window.location = aTag.href
|
||||
}
|
||||
card.href = goTo
|
||||
|
||||
// card.onclick = () => {
|
||||
// window.location = goTo
|
||||
// }
|
||||
return card
|
||||
}
|
||||
|
||||
|
|
|
@ -9,17 +9,43 @@ document.querySelectorAll('.schedule-category').forEach(node => {
|
|||
header.onclick = () => {
|
||||
if (!opened) {
|
||||
// open the table
|
||||
icon.style.transform = "rotate(180deg)"
|
||||
icon.style.transform = "rotate(0deg)"
|
||||
content.style.maxHeight = content.scrollHeight + "px"
|
||||
} else {
|
||||
// close the table
|
||||
icon.style.transform = "rotate(0deg)"
|
||||
icon.style.transform = "rotate(180deg)"
|
||||
content.style.maxHeight = null
|
||||
}
|
||||
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
|
||||
*/
|
||||
|
@ -70,8 +96,22 @@ let openModal = (url, isVideo) => {
|
|||
//document.body.style.height = '100vh'
|
||||
document.body.style.overflow = 'hidden'
|
||||
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 = () => {
|
||||
mediaModal.style.visibility = 'hidden'
|
||||
mediaModal.style.opacity = 0
|
||||
|
|
|
@ -53,6 +53,19 @@ body {
|
|||
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) {
|
||||
.container {
|
||||
width: 70%;
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
.cover {
|
||||
height: 13em;
|
||||
margin-top: -13em;
|
||||
background-color: rgba(230, 126, 34, 0.78);
|
||||
background-color: rgba(230, 126, 34, 0.4);
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ section {
|
|||
text-align: justify;
|
||||
margin: 0 auto;
|
||||
width: 80%;
|
||||
margin-top: 1.5em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
|
@ -332,16 +332,37 @@ section {
|
|||
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-category {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
@ -357,13 +378,13 @@ section {
|
|||
}
|
||||
|
||||
.schedule-category-collapse-icon {
|
||||
transform: rotate(180deg);
|
||||
color: #B12008;
|
||||
width: 1.5em;
|
||||
transition: all 0.1s ease-out;
|
||||
}
|
||||
|
||||
.schedule-category-table {
|
||||
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.1s ease-out;
|
||||
|
@ -376,7 +397,7 @@ section {
|
|||
margin-left: 2em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
margin-right: 40em;
|
||||
margin-right: 20em;
|
||||
|
||||
padding: 1em 2em 1em 2em;
|
||||
}
|
||||
|
@ -395,6 +416,14 @@ section {
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.schedule-category-hours {
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.schedule-category-hours .spearator {
|
||||
color: #bdc3c7;
|
||||
}
|
||||
|
||||
/* *****************************************************************************
|
||||
|
||||
* PRICING
|
||||
|
@ -450,7 +479,7 @@ section {
|
|||
|
||||
********************************************************************************/
|
||||
|
||||
.contact {
|
||||
.org-container {
|
||||
margin: 0 auto;
|
||||
width: 70%;
|
||||
}
|
||||
|
@ -541,13 +570,15 @@ section {
|
|||
.mentions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
color: #d35400;
|
||||
margin-top: 2em;
|
||||
margin-bottom: .5em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.mentions div {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
@ -589,17 +620,17 @@ RESPONSIVE
|
|||
@media (max-width: 900px) {
|
||||
|
||||
.cover-background {
|
||||
height: 30em;
|
||||
height: 23em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cover {
|
||||
height: 30em;
|
||||
margin-top: -30em;
|
||||
height: 23em;
|
||||
margin-top: -23em;
|
||||
}
|
||||
|
||||
.cover-content {
|
||||
height: 30em;
|
||||
height: 23em;
|
||||
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
@ -628,6 +659,10 @@ RESPONSIVE
|
|||
}
|
||||
|
||||
/* Mosaic level 2 */
|
||||
.mosaic-2 {
|
||||
grid-template-rows: 1fr 1fr;
|
||||
}
|
||||
|
||||
.mosaic-2, .mosaic-3 {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
@ -684,7 +719,7 @@ RESPONSIVE
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.contact {
|
||||
.org-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
@ -720,4 +755,7 @@ RESPONSIVE
|
|||
.media-modal {
|
||||
width: 90%;
|
||||
}
|
||||
.description {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
BIN
static/favicon.ico
Normal file
BIN
static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 101 KiB |
|
@ -35,7 +35,7 @@ Github: https://github.com/lefuturiste
|
|||
class="header-sub-title">
|
||||
Espace Condorcet Centre Social
|
||||
</a>
|
||||
<h1 class="header-title">Forum des associations</h1>
|
||||
<h1 class="header-title">Forum des associations 2020</h1>
|
||||
<div class="header-description">
|
||||
Cette année nous vous invitons à découvrir le forum virtuel des associations.
|
||||
</div>
|
||||
|
|
7
views/emails/test.twig
Normal file
7
views/emails/test.twig
Normal file
|
@ -0,0 +1,7 @@
|
|||
<p>
|
||||
This is a test
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Date: {{ date }}
|
||||
</p>
|
|
@ -73,8 +73,17 @@
|
|||
<div class="section-divider"></div>
|
||||
</div>
|
||||
<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 }}
|
||||
{% 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 %}
|
||||
{{ data.descriptionShort }}
|
||||
{% endif %}
|
||||
|
@ -88,8 +97,9 @@
|
|||
<h2>Crénaux</h2>
|
||||
<div class="section-divider"></div>
|
||||
</div>
|
||||
<div class="schedule">
|
||||
<div class="schedule org-container">
|
||||
{% for item in data.schedule %}
|
||||
{% if item.when|length > 0 %}
|
||||
<div class="schedule-category">
|
||||
<div class="schedule-category-header" title="Déroulez">
|
||||
<div class="schedule-category-name">
|
||||
|
@ -120,6 +130,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
|
@ -155,7 +166,7 @@
|
|||
<h2>Contact</h2>
|
||||
<div class="section-divider"></div>
|
||||
</div>
|
||||
<div class="contact">
|
||||
<div class="org-container contact">
|
||||
{% if data.contacts.person|length > 0 %}
|
||||
<div class="contact-item person">
|
||||
<div class="contact-icon">
|
||||
|
|
Loading…
Reference in a new issue