update
This commit is contained in:
parent
1bb080f7f1
commit
0c881c919b
15 changed files with 260 additions and 83 deletions
|
@ -9,6 +9,7 @@
|
|||
"@types/html-to-text": "^5.1.1",
|
||||
"@types/ioredis": "^4.17.0",
|
||||
"@types/jest": "^26.0.4",
|
||||
"@types/moment": "^2.13.0",
|
||||
"@types/mongoose": "^5.7.28",
|
||||
"@types/multer": "^1.4.3",
|
||||
"@types/multer-s3": "^2.7.7",
|
||||
|
@ -26,6 +27,7 @@
|
|||
"html-to-text": "^5.1.1",
|
||||
"ioredis": "^4.17.3",
|
||||
"jest": "^26.1.0",
|
||||
"moment": "^2.27.0",
|
||||
"mongoose": "^5.9.20",
|
||||
"multer": "^1.4.2",
|
||||
"multer-s3": "^2.9.0",
|
||||
|
|
|
@ -17,9 +17,9 @@ export default class Utils {
|
|||
bool = bool && (
|
||||
explored !== undefined && explored !== null
|
||||
)
|
||||
if (i - 1 === levels && isStr) {
|
||||
bool = bool && typeof explored === 'string' && explored.length > 0
|
||||
}
|
||||
}
|
||||
if (isStr) {
|
||||
bool = bool && typeof explored === 'string' && explored.length > 0
|
||||
}
|
||||
return bool
|
||||
}
|
||||
|
|
14
src/app.ts
14
src/app.ts
|
@ -16,6 +16,12 @@ import twig from 'twig'
|
|||
import EmailService from './EmailService'
|
||||
import ErrorController from './controllers/ErrorController'
|
||||
|
||||
process.on('unhandledRejection', (err) => {
|
||||
console.error(err)
|
||||
console.log('unhandledRejection!')
|
||||
process.exit()
|
||||
})
|
||||
|
||||
dotenv.config({
|
||||
path: __dirname + '/../.env'
|
||||
})
|
||||
|
@ -110,11 +116,7 @@ let main = async () => {
|
|||
|
||||
app.get('/500', ErrorController.internalError)
|
||||
|
||||
app.use((err: any, req: express.Request, res: express.Response, next: express.RequestHandler) => {
|
||||
console.error(err.stack)
|
||||
//res.status(res.statusCode).json({ success: false, error: err.stack })
|
||||
ErrorController.handle(500, 'Erreur interne', 'Ouups je sais pas quoi dire', '💥', err.stack)(req, res)
|
||||
})
|
||||
app.use(ErrorController.handleServerError)
|
||||
|
||||
app.use(ErrorController.notFoundHandler())
|
||||
|
||||
|
@ -123,4 +125,4 @@ let main = async () => {
|
|||
})
|
||||
}
|
||||
|
||||
main()
|
||||
main()
|
||||
|
|
|
@ -30,11 +30,22 @@ export default class AdminOrganizationController {
|
|||
let body: any = {
|
||||
token: AdminOrganizationController.generateToken(),
|
||||
createdAt: new Date(),
|
||||
slug: slugify(req.body.adminName).toLowerCase(),
|
||||
// start the slugs array
|
||||
slugs: [slugify(req.body.adminName)],
|
||||
...req.body,
|
||||
...{
|
||||
proposedVersion: {
|
||||
name: req.body.adminName
|
||||
name: req.body.adminName,
|
||||
contacts: {
|
||||
facebook: '',
|
||||
twitter: '',
|
||||
instagram: '',
|
||||
website: '',
|
||||
address: '',
|
||||
person: '',
|
||||
email: req.body.email,
|
||||
phone: ''
|
||||
}
|
||||
// descriptionShort: '',
|
||||
// descriptionLong: '',
|
||||
// contacts: [],
|
||||
|
@ -49,22 +60,35 @@ export default class AdminOrganizationController {
|
|||
}
|
||||
Organization.create(body).then(data => {
|
||||
AdminOrganizationController.sendEmailTokenUniversal(data)
|
||||
res.json({ success: true, data })
|
||||
res.json({ success: true, data, body })
|
||||
}).catch(err => res.status(400).json({ success: false, errors: err.errors }))
|
||||
}
|
||||
|
||||
static update(req: express.Request, res: express.Response) {
|
||||
let extra: any = {}
|
||||
if (req.body.name !== undefined) {
|
||||
extra.slug = slugify(req.body.name)
|
||||
}
|
||||
Organization.updateOne({ _id: req.params.id }, {
|
||||
...extra,
|
||||
...req.body,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.then(data => res.json({ success: true, data }))
|
||||
.catch(err => res.status(400).json({ success: false, errors: err.errors !== undefined ? err.errors : err }))
|
||||
Organization.findById(req.params.id)
|
||||
.then(data => {
|
||||
// generate extra slugs
|
||||
let extra: any = {}
|
||||
if (req.body.name !== undefined) {
|
||||
let slug = slugify(req.body.name)
|
||||
// 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'))) {
|
||||
currentSlugs = data.get('slugs')
|
||||
}
|
||||
if (currentSlugs.filter(s => s === slug).length === 0) {
|
||||
extra.slugs = currentSlugs.concat([slug])
|
||||
}
|
||||
}
|
||||
Organization.updateOne({ _id: req.params.id }, {
|
||||
...extra,
|
||||
...req.body,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.then(data => res.json({ success: true, data }))
|
||||
.catch(err => res.status(400).json({ success: false, errors: err.errors !== undefined ? err.errors : err }))
|
||||
})
|
||||
.catch(err => res.status(400).json({ success: false, errors: err }))
|
||||
}
|
||||
|
||||
static destroy(req: express.Request, res: express.Response) {
|
||||
|
|
|
@ -34,15 +34,19 @@ export default class DelegateController {
|
|||
})
|
||||
}
|
||||
|
||||
const next = (tag: any) => {
|
||||
const next = (tags: any) => {
|
||||
// only update proposedVersion
|
||||
let proposedVersion: any = req.body
|
||||
proposedVersion.tag = tag
|
||||
proposedVersion.descriptionLong = proposedVersion.descriptionLong.replace(/\n/g, '')
|
||||
proposedVersion.descriptionLong = sanitizeHtml(
|
||||
proposedVersion.descriptionLong,
|
||||
{ allowedTags: ['h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', 'li', 'b', 'i', 'abbr', 'strong', 'em', 'hr', 'br', 'div', 'pre'] }
|
||||
)
|
||||
proposedVersion.tags = tags
|
||||
|
||||
// sanitize long description
|
||||
if (Utils.isStrUsable(proposedVersion.descriptionLong)) {
|
||||
proposedVersion.descriptionLong = proposedVersion.descriptionLong.replace(/\n/g, '')
|
||||
proposedVersion.descriptionLong = sanitizeHtml(
|
||||
proposedVersion.descriptionLong,
|
||||
{ allowedTags: ['h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', 'li', 'b', 'i', 'abbr', 'strong', 'em', 'hr', 'br', 'div', 'pre'] }
|
||||
)
|
||||
}
|
||||
|
||||
// validate contact.address
|
||||
// validate all fields to not overflow
|
||||
|
@ -73,6 +77,19 @@ export default class DelegateController {
|
|||
MediaService.delete(organization.proposedVersion.cover.key, 'coverDeleted')
|
||||
}
|
||||
|
||||
// delete unused thumbnail
|
||||
// if the thumbnail is reset we must delete the old one only if it is unused in the published version
|
||||
if (
|
||||
Utils.isStrUsable(organization, 'proposedVersion.thumbnail.key') &&
|
||||
!Utils.isStrUsable(proposedVersion, 'thumbnail.key') &&
|
||||
!(
|
||||
Utils.isStrUsable(organization, 'publishedVersion.thumbnail.key') &&
|
||||
organization.publishedVersion.thumbnail.key === organization.proposedVersion.thumbnail.key
|
||||
)
|
||||
) {
|
||||
MediaService.delete(organization.proposedVersion.thumbnail.key, 'thumbnailDeleted')
|
||||
}
|
||||
|
||||
// format schedule, pricing
|
||||
if (!Array.isArray(proposedVersion.schedule)) {
|
||||
proposedVersion.schedule = []
|
||||
|
@ -93,22 +110,27 @@ export default class DelegateController {
|
|||
}).catch(err => res.status(400).json({ success: false, errors: err.errors !== undefined ? err.errors : err }))
|
||||
}
|
||||
|
||||
if (req.body.tag !== undefined && req.body.tag !== null && req.body.tag.length > 2) {
|
||||
if (Utils.isUsable(req.body, 'tags') && Array.isArray(req.body.tags)) {
|
||||
// skip the tag part if the tag didn't changed
|
||||
if (
|
||||
organization.proposedVersion.tag === undefined ||
|
||||
organization.proposedVersion.tag === null ||
|
||||
req.body.tag !== organization.proposedVersion.tag._id
|
||||
organization.proposedVersion.tags === undefined ||
|
||||
organization.proposedVersion.tags === null ||
|
||||
req.body.tags !== organization.proposedVersion.tags
|
||||
) {
|
||||
// if the tag is defined, search the tag id
|
||||
Tag.findById(req.body.tag).then(tag => {
|
||||
next(tag)
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
res.status(400).json({ success: false, errors: err, _note: 'The tag id provided is invalid' })
|
||||
let promises: Promise<string>[] = []
|
||||
req.body.tags.forEach((id: string) => {
|
||||
promises.push(new Promise((resolve, reject) => {
|
||||
Tag.findById(id).then((tag: any) => resolve(tag.get('_id'))).catch((err: any) => reject(err))
|
||||
}))
|
||||
})
|
||||
Promise.all(promises).then(() => {
|
||||
next(req.body.tags)
|
||||
}).catch((err) => {
|
||||
return res.status(400).json({ success: false, errors: err, _note: 'One of the tag id provided is invalid' })
|
||||
})
|
||||
} else {
|
||||
next(organization.tag)
|
||||
next(organization.tags)
|
||||
}
|
||||
} else {
|
||||
next(null)
|
||||
|
|
|
@ -13,6 +13,12 @@ export default class ErrorController {
|
|||
}
|
||||
}
|
||||
|
||||
static handleServerError(err: any, req: express.Request, res: express.Response, next: any) {
|
||||
console.error(err.stack)
|
||||
//res.status(res.statusCode).json({ success: false, error: err.stack })
|
||||
return ErrorController.handle(500, 'Erreur interne', 'Ouups je sais pas quoi dire', '💥', err.stack)(req, res)
|
||||
}
|
||||
|
||||
static notFoundHandler() {
|
||||
return ErrorController.handle(404, 'Page introuvable', 'Mais où peut donc se trouver cette page ?', '🔍 🕵️')
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import { IconService, IconInterface } from '../IconService'
|
|||
import IORedis from 'ioredis'
|
||||
import Tag from '../models/Tag'
|
||||
import ErrorController from './ErrorController'
|
||||
import Utils from '../Utils'
|
||||
import mongoose from 'mongoose'
|
||||
|
||||
export default class PublicController {
|
||||
|
||||
|
@ -19,45 +21,67 @@ export default class PublicController {
|
|||
// data: await client.get('hello')
|
||||
// })
|
||||
Tag.find().then(tags => {
|
||||
Organization.find().then(organizations => {
|
||||
let isProposed = Utils.isStrUsable(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, [])
|
||||
}
|
||||
Organization.find(isProposed ? { _id: req.query.only } : {}).then(organizations => {
|
||||
if (!isProposed) {
|
||||
organizations = organizations.filter(o => o.get('publishedAt') !== undefined && o.get('publishedAt') !== null)
|
||||
}
|
||||
res.render('home.twig', {
|
||||
isProposed,
|
||||
tags,
|
||||
tagsJSON: JSON.stringify(tags),
|
||||
organizationsJSON: JSON.stringify(organizations
|
||||
.filter(o => o.get('publishedAt') !== undefined && o.get('publishedAt') !== null)
|
||||
.map(o => {
|
||||
const version = o.get('publishedVersion')
|
||||
const version = isProposed ? o.get('proposedVersion'): o.get('publishedVersion')
|
||||
return {
|
||||
_id: o._id,
|
||||
name: version.name,
|
||||
description: version.descriptionShort,
|
||||
thumbnail: version.thumbnail.location,
|
||||
tag: version.tag === null ? 'tag_not_found' : version.tag._id,
|
||||
slug: o.get('slug')
|
||||
tags: version.tags === null ? 'tags_not_found' : version.tags,
|
||||
slugs: o.get('slugs'),
|
||||
isProposed
|
||||
}
|
||||
})
|
||||
)
|
||||
})
|
||||
}).catch(err => () => {
|
||||
console.log(err)
|
||||
return ErrorController.handleServerError(err, req, res, [])
|
||||
})
|
||||
}).catch(err => () => {
|
||||
console.log(err)
|
||||
return ErrorController.handleServerError(err, req, res, [])
|
||||
})
|
||||
}
|
||||
|
||||
static async organization(req: express.Request, res: express.Response) {
|
||||
Organization.find({ slug: req.params.slug }).then(data => {
|
||||
Organization.find({ slugs: { '$in': req.params.slug } }).then(data => {
|
||||
if (data.length === 0) {
|
||||
return ErrorController.notFoundHandler()(req, res)
|
||||
} else {
|
||||
const org = data[0]
|
||||
let version = org.get('publishedVersion')
|
||||
let lastPublished = org.get('publishedAt')
|
||||
let isProposed = false
|
||||
if (req.query.version === 'proposed') {
|
||||
isProposed = true
|
||||
lastPublished = org.get('updatedAt')
|
||||
version = org.get('proposedVersion')
|
||||
} else if (org.get('publishedAt') === undefined || org.get('publishedAt') === null) {
|
||||
} else if (lastPublished === undefined || lastPublished === null) {
|
||||
return ErrorController.notFoundHandler()(req, res)
|
||||
}
|
||||
if (version.contacts !== null && version.contacts !== undefined) {
|
||||
if (typeof version.contacts.address === 'string') {
|
||||
// if (lastPublished !== null) {
|
||||
// lastPublished = lastPublished
|
||||
// }
|
||||
if (Utils.isUsable(version.contacts)) {
|
||||
if (Utils.isStrUsable(version.contacts, 'address')) {
|
||||
version.contacts.address = version.contacts.address.split('\n')
|
||||
}
|
||||
if (typeof version.contacts.phone === 'string') {
|
||||
if (Utils.isStrUsable(version.contacts, 'phone')) {
|
||||
let phone = version.contacts.phone
|
||||
if (phone.indexOf('+33') === 0) {
|
||||
phone = '0' + phone.substr(3)
|
||||
|
@ -83,10 +107,16 @@ export default class PublicController {
|
|||
}
|
||||
res.render('organization.twig', {
|
||||
layout: 'standalone',
|
||||
data: version
|
||||
data: version,
|
||||
lastPublished: lastPublished.toLocaleDateString('fr-FR') + ' ' + lastPublished.toLocaleTimeString('fr-FR', { timezone: '+2' }).substr(0, 5),
|
||||
isProposed,
|
||||
id: org.get('_id')
|
||||
})
|
||||
}
|
||||
}).catch(_ => res.status(404).render('not-found.twig'))
|
||||
}).catch(err => () => {
|
||||
console.log(err)
|
||||
return ErrorController.handleServerError(err, req, res, [])
|
||||
})
|
||||
}
|
||||
|
||||
static async about(req: express.Request, res: express.Response) {
|
||||
|
|
|
@ -74,14 +74,14 @@ const OrganizationVersion = {
|
|||
priceLabel: { type: String, required: true },
|
||||
description: { type: String }
|
||||
}],
|
||||
tag: [Tag]
|
||||
tags: [{ type: String }]
|
||||
}
|
||||
|
||||
const Organization = new Schema({
|
||||
adminName: { type: String, required: true },
|
||||
email: { type: String, required: true },
|
||||
token: { type: String, required: true },
|
||||
slug: [{ type: String }], // aliases system
|
||||
slugs: [{ type: String }], // aliases system
|
||||
validationState: {
|
||||
type: AllowedString,
|
||||
required: true,
|
||||
|
|
|
@ -181,6 +181,8 @@
|
|||
margin-bottom: 1em;
|
||||
box-shadow: 0 0 8px 0px rgba(0,0,0,0.1);
|
||||
transition: all 0.2s;
|
||||
height: 12em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
|
@ -202,7 +204,7 @@
|
|||
}
|
||||
|
||||
.card-content {
|
||||
/* width: 100%; */
|
||||
width: 100%;
|
||||
padding: 1.5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -238,12 +240,14 @@
|
|||
color: #34495E;
|
||||
margin: 0;
|
||||
line-height: 1.6em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card-link {
|
||||
color: #0029FF;
|
||||
opacity: 0.75;
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
right: .5em;
|
||||
bottom: 0;
|
||||
margin-bottom: -.5em;
|
||||
}
|
||||
|
||||
@media (max-width: 1350px) {
|
||||
|
|
|
@ -10,11 +10,6 @@ let navContent = document.getElementById('nav-content')
|
|||
let mosaic = document.getElementById('mosaic')
|
||||
let mosaicHeader = document.getElementById('mosaic-header')
|
||||
|
||||
organizations = organizations.map(org => {
|
||||
org.tag = tags.filter(t => t._id === org.tag)[0]
|
||||
return org
|
||||
})
|
||||
|
||||
navEnabler.onclick = async () => {
|
||||
if (!navOpened) {
|
||||
// open the menu
|
||||
|
@ -105,28 +100,36 @@ function renderCard(organization) {
|
|||
titleContainer.appendChild(title)
|
||||
|
||||
let icon = createEl('card-icon')
|
||||
icon.innerHTML = `<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 ${organization.tag.icon.width} ${organization.tag.icon.height}">
|
||||
<path fill="currentColor" d="${organization.tag.icon.path}"></path>
|
||||
</svg>`
|
||||
if (Array.isArray(organization.tags) && organization.tags.length > 0) {
|
||||
let tag = tags.filter(tag => organization.tags[0] === tag._id)[0]
|
||||
icon.innerHTML = `<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 ${tag.icon.width} ${tag.icon.height}">
|
||||
<path fill="currentColor" d="${tag.icon.path}"></path>
|
||||
</svg>`
|
||||
}
|
||||
titleContainer.appendChild(icon)
|
||||
upperContent.appendChild(titleContainer)
|
||||
|
||||
let description = createEl('card-description')
|
||||
description.textContent = organization.description
|
||||
upperContent.appendChild(description)
|
||||
|
||||
let link = createEl('card-link')
|
||||
let aTag = createEl(0, 'a')
|
||||
aTag.href = "/association/" + organization.slug
|
||||
//let link = createEl('card-link')
|
||||
let aTag = createEl('card-link', 'a')
|
||||
aTag.href = "/association/" + organization.slugs[organization.slugs.length - 1]
|
||||
if (organization.isProposed) {
|
||||
aTag.href += "?version=proposed"
|
||||
}
|
||||
aTag.textContent = "En savoir plus"
|
||||
link.appendChild(aTag)
|
||||
description.appendChild(aTag)
|
||||
|
||||
upperContent.appendChild(description)
|
||||
//link.appendChild(aTag)
|
||||
content.appendChild(upperContent)
|
||||
content.appendChild(link)
|
||||
//content.appendChild(link)
|
||||
card.appendChild(content)
|
||||
|
||||
card.onclick = () => {
|
||||
|
@ -152,7 +155,7 @@ function enableTag(node) {
|
|||
if (!all) {
|
||||
tagId = node.attributes['data-tag-id'].value
|
||||
}
|
||||
let data = organizations.filter(orga => orga.tag._id === tagId || all)
|
||||
let data = organizations.filter(orga => orga.tags.filter(id => id === tagId).length > 0 || all)
|
||||
let cards = renderMosaic(data)
|
||||
if (currentCardContainer !== null) {
|
||||
mosaic.removeChild(currentCardContainer)
|
||||
|
|
|
@ -23,6 +23,35 @@ a:hover {
|
|||
color: #2980b9;
|
||||
}
|
||||
|
||||
/* sticky footer */
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.up-footer {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
.sticky-footer {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Porposed alert */
|
||||
.proposed-alert {
|
||||
position: fixed;
|
||||
z-index: 9999999;
|
||||
left: 1em;
|
||||
bottom: 2em;
|
||||
padding: 1em;
|
||||
font-weight: bold;
|
||||
border-radius: 3px;
|
||||
text-transform: uppercase;
|
||||
border: 1px solid #c0392b;
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@media (max-width: 1600px) {
|
||||
.container {
|
||||
|
|
|
@ -538,13 +538,26 @@ section {
|
|||
|
||||
********************************************************************************/
|
||||
|
||||
.mentions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
color: #d35400;
|
||||
margin-top: 2em;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
.mentions div {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 50% 25% 25%;
|
||||
grid-template-rows: 1fr;
|
||||
height: 1em;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.footer div:nth-child(1) {
|
||||
|
@ -559,6 +572,9 @@ section {
|
|||
background-color: rgb(253, 110, 11, .83);
|
||||
}
|
||||
|
||||
/**
|
||||
RESPONSIVE
|
||||
**/
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.schedule-category-days-container {
|
||||
|
|
|
@ -21,6 +21,7 @@ Github: https://github.com/lefuturiste
|
|||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<div class="up-footer">
|
||||
{% if layout is not defined %}
|
||||
<div class="header">
|
||||
<div class="container header-container">
|
||||
|
@ -54,6 +55,17 @@ Github: https://github.com/lefuturiste
|
|||
{% else %}
|
||||
{% block content %}{% endblock %}
|
||||
{% endif %}
|
||||
{% if isProposed is defined and isProposed == true %}
|
||||
<div class="proposed-alert">
|
||||
! Version proposé !
|
||||
{# <div class="proposed-alert-content">
|
||||
</div> #}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="sticky-footer">
|
||||
{% block footer %}{% endblock %}
|
||||
</div>
|
||||
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{% block content %}
|
||||
<div class="header">
|
||||
<div class="container header-container">
|
||||
<a href="/" class="return">
|
||||
<a href="{% if isProposed is defined and isProposed == true %}/?only={{ id }}{% else %}/{% endif %}" class="return">
|
||||
<div class="return-icon">
|
||||
<svg aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M256 504C119 504 8 393 8 256S119 8 256 8s248 111 248 248-111 248-248 248zM142.1 273l135.5 135.5c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L226.9 256l101.6-101.6c9.4-9.4 9.4-24.6 0-33.9l-17-17c-9.4-9.4-24.6-9.4-33.9 0L142.1 239c-9.4 9.4-9.4 24.6 0 34z"></path>
|
||||
|
@ -66,17 +66,21 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if data.descriptionLong|length > 0 %}
|
||||
{# {% if data.descriptionLong|length > 0 %} #}
|
||||
<section>
|
||||
<div class="section-title">
|
||||
<h2>Présentation</h2>
|
||||
<div class="section-divider"></div>
|
||||
</div>
|
||||
<div class="description">
|
||||
{{ data.descriptionLong|raw }}
|
||||
{% if data.descriptionLong is not null and data.descriptionLong|length > 7 %}
|
||||
{{ data.descriptionLong|raw }}
|
||||
{% else %}
|
||||
{{ data.descriptionShort }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
{# {% endif %} #}
|
||||
|
||||
{% if data.schedule|length > 0 %}
|
||||
<section>
|
||||
|
@ -274,6 +278,17 @@
|
|||
</section>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
<div class="mentions">
|
||||
<div class="advice">
|
||||
Contenu rédigée par l'une des associations participant à associations.espacecondorcet.org
|
||||
</div>
|
||||
<div class="last-update">
|
||||
Dernière mise à jour le {{ lastPublished }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div></div>
|
||||
<div></div>
|
||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -667,6 +667,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.2.tgz#857a118d8634c84bba7ae14088e4508490cd5da5"
|
||||
integrity sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==
|
||||
|
||||
"@types/moment@^2.13.0":
|
||||
version "2.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/moment/-/moment-2.13.0.tgz#604ebd189bc3bc34a1548689404e61a2a4aac896"
|
||||
integrity sha1-YE69GJvDvDShVIaJQE5hoqSqyJY=
|
||||
dependencies:
|
||||
moment "*"
|
||||
|
||||
"@types/mongodb@*":
|
||||
version "3.5.25"
|
||||
resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-3.5.25.tgz#ab187db04d79f8e3f15af236327dc9139d9d4736"
|
||||
|
@ -3471,6 +3478,11 @@ mkdirp@^0.5.1:
|
|||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
moment@*, moment@^2.27.0:
|
||||
version "2.27.0"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d"
|
||||
integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==
|
||||
|
||||
mongodb@3.5.9:
|
||||
version "3.5.9"
|
||||
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.5.9.tgz#799b72be8110b7e71a882bb7ce0d84d05429f772"
|
||||
|
|
Loading…
Reference in a new issue