update and error handling
This commit is contained in:
parent
fa6bc5f3f3
commit
1bb080f7f1
12 changed files with 203 additions and 30 deletions
|
@ -67,7 +67,7 @@ export default class MediaService {
|
|||
// @ts-ignore
|
||||
contentType: file.contentType,
|
||||
// @ts-ignore
|
||||
location: file.location,
|
||||
location: file.location.replace('http://', 'https://'),
|
||||
// @ts-ignore
|
||||
size: file.size,
|
||||
// @ts-ignore
|
||||
|
|
17
src/app.ts
17
src/app.ts
|
@ -14,6 +14,7 @@ import PublicController from './controllers/PublicController'
|
|||
import cors from 'cors'
|
||||
import twig from 'twig'
|
||||
import EmailService from './EmailService'
|
||||
import ErrorController from './controllers/ErrorController'
|
||||
|
||||
dotenv.config({
|
||||
path: __dirname + '/../.env'
|
||||
|
@ -42,6 +43,7 @@ let main = async () => {
|
|||
console.log('> App: Connected to mongodb')
|
||||
})
|
||||
|
||||
|
||||
app.set("twig options", {
|
||||
allow_async: true,
|
||||
strict_variables: false
|
||||
|
@ -49,11 +51,6 @@ let main = async () => {
|
|||
app.use(cors())
|
||||
app.use(bodyParser.json())
|
||||
|
||||
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 })
|
||||
})
|
||||
|
||||
app.get('/', PublicController.home)
|
||||
app.get('/association/:slug', PublicController.organization)
|
||||
app.get('/a-propos', PublicController.about)
|
||||
|
@ -111,6 +108,16 @@ let main = async () => {
|
|||
|
||||
app.use(express.static(path.resolve('./static')))
|
||||
|
||||
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.notFoundHandler())
|
||||
|
||||
app.listen(port, host, () => {
|
||||
console.log(`> App: API listening on ${host}:${port}`)
|
||||
})
|
||||
|
|
23
src/controllers/ErrorController.ts
Normal file
23
src/controllers/ErrorController.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import * as express from 'express'
|
||||
|
||||
export default class ErrorController {
|
||||
static handle(code: number, title: string, subTitle: string, emoji: string, details = '') {
|
||||
return (req: express.Request, res: express.Response) => {
|
||||
res.status(code).render('error.twig', {
|
||||
title,
|
||||
subTitle,
|
||||
emoji,
|
||||
layout: -1,
|
||||
details
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
static notFoundHandler() {
|
||||
return ErrorController.handle(404, 'Page introuvable', 'Mais où peut donc se trouver cette page ?', '🔍 🕵️')
|
||||
}
|
||||
|
||||
static internalError(req: express.Request, res: express.Response) {
|
||||
console.log(res.locals.blabla.blabla)
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import fs from 'fs'
|
|||
import { IconService, IconInterface } from '../IconService'
|
||||
import IORedis from 'ioredis'
|
||||
import Tag from '../models/Tag'
|
||||
import ErrorController from './ErrorController'
|
||||
|
||||
export default class PublicController {
|
||||
|
||||
|
@ -43,14 +44,14 @@ export default class PublicController {
|
|||
static async organization(req: express.Request, res: express.Response) {
|
||||
Organization.find({ slug: req.params.slug }).then(data => {
|
||||
if (data.length === 0) {
|
||||
return res.status(404).render('not-found.twig')
|
||||
return ErrorController.notFoundHandler()(req, res)
|
||||
} else {
|
||||
const org = data[0]
|
||||
let version = org.get('publishedVersion')
|
||||
if (req.query.version === 'proposed') {
|
||||
version = org.get('proposedVersion')
|
||||
} else if (org.get('publishedAt') === undefined || org.get('publishedAt') === null) {
|
||||
return res.status(404).render('not-found.twig')
|
||||
return ErrorController.notFoundHandler()(req, res)
|
||||
}
|
||||
if (version.contacts !== null && version.contacts !== undefined) {
|
||||
if (typeof version.contacts.address === 'string') {
|
||||
|
@ -74,6 +75,12 @@ export default class PublicController {
|
|||
version.contacts.phoneSplit = phoneSplit
|
||||
}
|
||||
}
|
||||
if (Array.isArray(version.gallery)) {
|
||||
version.gallery = version.gallery.slice(0, 5).map((media: any) => {
|
||||
media.isVideo = media.contentType.indexOf('video/') !== -1
|
||||
return media
|
||||
})
|
||||
}
|
||||
res.render('organization.twig', {
|
||||
layout: 'standalone',
|
||||
data: version
|
||||
|
|
|
@ -74,14 +74,14 @@ const OrganizationVersion = {
|
|||
priceLabel: { type: String, required: true },
|
||||
description: { type: String }
|
||||
}],
|
||||
tag: { type: Tag }
|
||||
tag: [Tag]
|
||||
}
|
||||
|
||||
const Organization = new Schema({
|
||||
adminName: { type: String, required: true },
|
||||
email: { type: String, required: true },
|
||||
token: { type: String, required: true },
|
||||
slug: { type: String, required: true },
|
||||
slug: [{ type: String }], // aliases system
|
||||
validationState: {
|
||||
type: AllowedString,
|
||||
required: true,
|
||||
|
|
35
static/assets/error.css
Normal file
35
static/assets/error.css
Normal file
|
@ -0,0 +1,35 @@
|
|||
.error-container {
|
||||
width: 100%;
|
||||
margin-top: 4em;
|
||||
}
|
||||
|
||||
.error {
|
||||
width: 60%;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.error-title {
|
||||
font-family: 'Roboto Slab', serif;
|
||||
}
|
||||
|
||||
.error-icons {
|
||||
font-size: 5em;
|
||||
margin-bottom: .25em;
|
||||
}
|
||||
|
||||
.expert {
|
||||
text-align: left;
|
||||
padding: 1em;
|
||||
background-color: black;
|
||||
color: rgba(0, 255, 0);
|
||||
border: 2px solid gray;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
@media (max-width: 1350px) {
|
||||
.error {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
}
|
||||
|
||||
.header-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
@ -15,6 +16,9 @@
|
|||
}
|
||||
|
||||
.header-menu {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
@ -246,6 +250,9 @@
|
|||
.card-container {
|
||||
width: 100%;
|
||||
}
|
||||
.header-left {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
|
@ -261,7 +268,8 @@
|
|||
}
|
||||
.header-menu {
|
||||
justify-content: center;
|
||||
margin-top: 1em;
|
||||
position: relative;
|
||||
margin-top: 0;
|
||||
}
|
||||
.header-content {
|
||||
padding: 0;
|
||||
|
|
|
@ -24,21 +24,61 @@ document.querySelectorAll('.schedule-category').forEach(node => {
|
|||
* Gallery modal to view media in large
|
||||
*/
|
||||
let mediaModal = document.querySelector('#media-modal')
|
||||
let mediaModalImage = document.querySelector('#media-modal-image')
|
||||
let mediaModalContent = document.querySelector('#media-modal-content')
|
||||
// let mediaModalImage = document.querySelector('#media-modal img')
|
||||
// let mediaModalVideo = document.querySelector('#media-modal video')
|
||||
// let mediaModalSource = document.querySelector('#media-modal video source')
|
||||
|
||||
let openModal = url => {
|
||||
// function disableScroll() {
|
||||
// // Get the current page scroll position
|
||||
// scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
// scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
|
||||
|
||||
// // if any scroll is attempted, set this to the previous value
|
||||
// window.onscroll = function() {
|
||||
// window.scrollTo(scrollLeft, scrollTop);
|
||||
// };
|
||||
// }
|
||||
|
||||
// function enableScroll() {
|
||||
// window.onscroll = function() {};
|
||||
// }
|
||||
|
||||
|
||||
let openModal = (url, isVideo) => {
|
||||
mediaModal.style.visibility = 'visible'
|
||||
mediaModal.style.opacity = 1
|
||||
mediaModalContent.innerHTML = ""
|
||||
|
||||
let attr = document.createAttribute('src')
|
||||
attr.value = url
|
||||
mediaModalImage.attributes.setNamedItem(attr)
|
||||
document.body.style.height = "100vh"
|
||||
document.body.style.overflow = "hidden"
|
||||
let el = null
|
||||
if (isVideo) {
|
||||
el = document.createElement('video')
|
||||
el.setAttribute('controls', '')
|
||||
el.setAttribute('autoplay', '')
|
||||
el.setAttribute('name', 'media')
|
||||
let source = document.createElement('source')
|
||||
source.setAttribute('src', url)
|
||||
source.setAttribute('type', 'video/mp4')
|
||||
el.appendChild(source)
|
||||
} else {
|
||||
el = document.createElement('img')
|
||||
el.attributes.setNamedItem(attr)
|
||||
}
|
||||
mediaModalContent.appendChild(el)
|
||||
//document.body.style.height = '100vh'
|
||||
document.body.style.overflow = 'hidden'
|
||||
document.body.style.touchAction = 'none'
|
||||
}
|
||||
|
||||
let closeModal = () => {
|
||||
mediaModal.style.visibility = 'hidden'
|
||||
mediaModal.style.opacity = 0
|
||||
document.body.style.overflow = "initial"
|
||||
document.body.style.height = "initial"
|
||||
document.body.style.overflow = 'initial'
|
||||
document.body.style.height = 'initial'
|
||||
let video = document.querySelector('#media-modal video')
|
||||
if (video !== null) {
|
||||
video.pause()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,7 +118,6 @@
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 3.5em;
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
@ -131,12 +130,13 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.media-overlay i {
|
||||
.media-overlay svg {
|
||||
width: 3.5em;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.media-overlay i:hover {
|
||||
.media-overlay svg:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
|
@ -194,6 +194,7 @@
|
|||
} */
|
||||
|
||||
.media {
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
background-size: cover;
|
||||
|
@ -204,7 +205,7 @@
|
|||
* Media modal
|
||||
*/
|
||||
.media-modal-container {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
z-index: 99;
|
||||
|
@ -226,11 +227,15 @@
|
|||
width: 50%;
|
||||
}
|
||||
|
||||
.media-modal img {
|
||||
.media-modal .media-modal-content {
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.media-modal img, .media-modal video {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.media-close {
|
||||
position: absolute;
|
||||
width: 1.5em;
|
||||
|
@ -559,6 +564,9 @@ section {
|
|||
.schedule-category-days-container {
|
||||
margin-right: 25em;
|
||||
}
|
||||
.media-modal {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -637,6 +645,10 @@ section {
|
|||
grid-column: 1 / span 2;
|
||||
}
|
||||
|
||||
.media-modal {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.schedule-category-header {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
|
@ -689,4 +701,7 @@ section {
|
|||
.return-title {
|
||||
display: none;
|
||||
}
|
||||
.media-modal {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,8 @@
|
|||
<!--
|
||||
Site développé par Matthieu Bessat - lefuturiste -
|
||||
Portfolio: https://lefuturiste.fr
|
||||
Github: https://github.com/lefuturiste
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
|
26
views/error.twig
Normal file
26
views/error.twig
Normal file
|
@ -0,0 +1,26 @@
|
|||
{% extends "./base.twig" %}
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="/assets/error.css" />
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="error-container">
|
||||
<div class="error">
|
||||
<div class="error-icons">
|
||||
{{ emoji }}
|
||||
</div>
|
||||
<hr>
|
||||
<h1 class="error-title">{{ title }}</h1>
|
||||
<h4 class="error-sub-title">{{ subTitle }}</h4>
|
||||
<hr>
|
||||
{% if details|length > 0 %}
|
||||
<p>Pour les experts voici les détails :</p>
|
||||
<div class="expert">
|
||||
<pre>
|
||||
{{ details }}
|
||||
</pre>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -38,18 +38,25 @@
|
|||
{% if data.gallery|length > 0 %}
|
||||
<div class="media-mosaic mosaic-{{ data.gallery|length }}">
|
||||
{% for media in data.gallery %}
|
||||
<div class="media-container" onclick="openModal('{{ media.location }}')">
|
||||
<div class="media" style="background-image: url({{ media.location }})"></div>
|
||||
<div class="media-container" onclick="openModal('{{ media.location }}', {{ media.isVideo }})">
|
||||
<div
|
||||
class="media {% if media.isVideo %}media-video-bg{% endif %}"
|
||||
{% if not media.isVideo %}style="background-image: url({{ media.location }})"{% endif %}></div>
|
||||
{% if media.isVideo %}
|
||||
<div class="media-overlay">
|
||||
<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 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm115.7 272l-176 101c-15.8 8.8-35.7-2.5-35.7-21V152c0-18.4 19.8-29.8 35.7-21l176 107c16.4 9.2 16.4 32.9 0 42z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{# <div class="media-container media-1-2">
|
||||
<div class="media" style="background-image: url({{ data.gallery[2].location }})"></div>
|
||||
<div class="media-overlay"><i class="fas fa-play-circle"></i></div>
|
||||
</div> #}
|
||||
</div>
|
||||
<div class="media-modal-container" id="media-modal">
|
||||
<div class="media-modal">
|
||||
<img src="" id="media-modal-image" />
|
||||
<div class="media-modal-content" id="media-modal-content">
|
||||
|
||||
</div>
|
||||
<div class="media-close" onclick="closeModal()">
|
||||
<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 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z"></path>
|
||||
|
|
Loading…
Reference in a new issue