update and error handling

This commit is contained in:
root 2020-07-18 10:43:13 +00:00
parent fa6bc5f3f3
commit 1bb080f7f1
12 changed files with 203 additions and 30 deletions

View file

@ -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

View file

@ -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}`)
})

View 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)
}
}

View file

@ -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

View file

@ -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
View 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%;
}
}

View file

@ -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;

View file

@ -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()
}
}

View file

@ -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%;
}
}

View file

@ -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
View 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 %}

View file

@ -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>