Commit 1d5d83c8 authored by Floréal Cabanettes's avatar Floréal Cabanettes

Add chip to login / pass to panel/website page / logout + check login status + refactoring + etc

parent 73c986ef
......@@ -16,6 +16,7 @@ from view.register import page as register
from view.panel import page as panel
from exceptions import InvalidPassword, NotActiveUser
from functions import is_authenticated
from settings import SECRET_KEY
......@@ -39,10 +40,18 @@ db = MongoEngine(app)
@app.context_processor
def inject_default_data():
return dict({
data = {
"locale": LOCALE,
"locales": [LOCALE],
})
"email": None,
"dark": True,
"show_search": True
}
if is_authenticated():
data["email_hash"] = hashlib.md5(session["email"].encode()).hexdigest()
data["name"] = session["name"]
data["role"] = session["role"]
return dict(data)
@app.route('/')
......@@ -71,7 +80,8 @@ def login():
email = request.args.get("email")
if "after" in request.args and request.args.get("after") is not None:
after = request.args.get("after")
return render_template("web/login.html", email=email, after=after, title=_("Login") + " | " + SITE_NAME)
return render_template("web/login.html", email=email, after=after, title=_("Login") + " | " + SITE_NAME,
show_search=False)
email = request.form['email']
password = request.form['password']
after = None
......@@ -99,6 +109,7 @@ def login():
session["email"] = email
session["is_authenticated"] = True
session["name"] = user.name
session["role"] = user.role
return redirect("/" if after is None else after)
......
from flask import session
import random
import string
......@@ -6,3 +7,7 @@ def random_string(string_length=50):
"""Generate a random string of letters and digits """
letters_and_digits = string.ascii_letters + string.digits
return ''.join(random.choice(letters_and_digits) for i in range(string_length))
def is_authenticated():
return "is_authenticated" in session and session["is_authenticated"] is True
......@@ -51,4 +51,8 @@ html {
header {
z-index: 1001 !important;
}
.v-menu__content.menuable__content__active {
top: 8px !important;
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg4"
sodipodi:docname="account-dark.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="793"
inkscape:window-height="480"
id="namedview6"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="0"
inkscape:current-layer="svg4" />
<path
d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z"
id="path2"
style="fill:#ffffff;fill-opacity:1" />
</svg>
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z" /></svg>
\ No newline at end of file
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -23,38 +23,61 @@ Vue.directive('blur', {
});
})(jQuery);
init = function(locale, dark=true) {
init = function(locale, email_hash=null, name=null, dark=true, show_search=true, role="basic") {
LANG = locale;
eventBus = new Vue();
dark = dark !== null && dark !== undefined && dark !== "false" && dark !== "False";
show_search = show_search !== null && show_search !== undefined && show_search !== "false"
&& show_search !== "False";
app = new Vue({
vuetify: new Vuetify({
theme: {
dark: dark,
dark: dark === true || dark === "True",
}
}),
delimiters: ['((', '))'],
el: '#app',
data: {
show_alert: false,
message_alert: null,
type_alert: "error",
dark: true,
email_hash: email_hash,
user_role: role,
loadings: 0,
logged: email_hash && email_hash !== "None" && email_hash !== "null" && email_hash !== "none",
message_alert: null,
name: name,
show_search: show_search,
search: false,
searchText: "",
searchFieldColor: dark ? "white": "black",
menuItems: [
{title: "Home", icon: "mdi-news"},
{title: "Recipes", icon: "mdi-news"},
],
searchText: "",
show_alert: false,
snackbar: false,
snackbar_color: "info",
snackbar_message: null,
snackbar_multiline: false,
type_alert: "error",
windowSize: {
x: 0,
y: 0
},
snackbar: false,
snackbar_message: null,
snackbar_color: "info",
snackbar_multiline: false,
loadings: 0,
menu: false,
},
computed: {
user_role_name() {
switch (this.user_role) {
case "admin":
return tr("Admin")
case "moderator":
return tr("Moderator")
case "editor":
return tr("Editor")
default:
return tr("Simple user")
}
},
avatar_src() {
return 'https://www.gravatar.com/avatar/' + email_hash +
'?default=http://www.flo-art.fr/static/images/account-' + (dark ? '-dark' : '') + '.png';
}
},
methods: {
alert(message, type_message) {
......
......@@ -3,7 +3,7 @@
{% block script %}
{{ super() }}
<script src="/static/js/vue.js" defer></script>
<script src="/static/js/vuetify-v2.0.10.min.js" defer></script>
<script src="/static/js/vuetify-v2.0.18.min.js" defer></script>
<script src="/static/js/jquery-3.4.1.min.js" defer></script>
<script src="/static/js/axios.min.js" defer></script>
<script src="/static/js/translate.js" defer></script>
......@@ -20,12 +20,12 @@
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="/static/css/materialdesignicons.min.css">
<link rel="stylesheet" type="text/css" href="/static/css/vuetify-v2.0.10.min.css">
<link rel="stylesheet" type="text/css" href="/static/css/vuetify-v2.0.18.min.css">
<link rel="stylesheet" type="text/css" href="/static/css/recipen.css">
{% endblock %}
{% block body_attr %}
onload="init('{{ locale }}');"
onload="init('{{ locale }}', '{{ email_hash }}', '{{ name }}', '{{ dark }}', '{{ show_search }}', '{{ role }}');"
{% endblock %}
{% block body %}
......
{% extends "basis.html" %}
{% block appbody %}
<v-app-bar
absolute
color="#CA2C0A"
dense
{# fade-img-on-scroll#}
scroll-target="#scrolling-techniques-5"
scroll-threshold="500"
>
<v-app-bar
absolute
color="#CA2C0A"
dense
{# fade-img-on-scroll#}
scroll-target="#scrolling-techniques-5"
scroll-threshold="500"
>
<template v-slot:img="{ props }">
<v-img
v-bind="props"
gradient="to top right, rgba(55,236,186,.7), rgba(25,32,72,.7)"
></v-img>
<v-img
v-bind="props"
gradient="to top right, rgba(55,236,186,.7), rgba(25,32,72,.7)"
></v-img>
</template>
<v-app-bar-nav-icon></v-app-bar-nav-icon>
......@@ -23,77 +23,137 @@
<div class="flex-grow-1"></div>
<v-btn icon @click="showHideSearch()">
<v-icon>mdi-magnify</v-icon>
</v-btn><v-text-field :color="searchFieldColor" v-show="search" ref="search" id="search" @keydown.esc="showHideSearch()"
@keydown.enter="launchSearch()" v-model="searchText" @blur="searchBoxBlur()" @focus="searchLaunched=false"></v-text-field>
</v-app-bar>
<v-sheet
id="scrolling-techniques-5"
class="overflow-y-auto"
max-height="100vh"
min-height="100%"
style="background: none !important;"
>
<v-container style="padding-top: 37px; display: table; padding-left: 0; margin-left: 0; margin-right: 0; max-width: none;" fill-height>
{# <div style="width: 260px; display: table-cell; vertical-align: top; height: 100%;">#}
<v-navigation-drawer
:expand-on-hover="windowSize.x < 1300"
permanent
{# absolute#}
style="z-index: 0; display: table-cell; vertical-align: top; height: 100%;"
<v-icon>mdi-magnify</v-icon>
</v-btn>
<v-text-field :color="searchFieldColor" v-show="search" ref="search" id="search" @keydown.esc="showHideSearch()"
@keydown.enter="launchSearch()" v-model="searchText" @blur="searchBoxBlur()"
@focus="searchLaunched=false"></v-text-field>
<v-menu
v-model="menu"
top
right
transition="scale-transition"
origin="top right"
>
<template v-slot:activator="{ on }">
<v-chip
pill
v-on="on"
>
<v-avatar left>
<v-img :src="avatar_src"></v-img>
</v-avatar>
<b style="padding-left: 5px; padding-right: 5px;">{{ name }}</b>
</v-chip>
</template>
<v-card width="300" class="card-user-menu">
<v-list dark>
<v-list-item>
<v-list-item-avatar>
<v-img :src="avatar_src"></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>(( name ))</v-list-item-title>
<v-list-item-subtitle>(( user_role_name ))</v-list-item-subtitle>
</v-list-item-content>
{# <v-list-item-action>#}
{# <v-btn#}
{# icon#}
{# @click="menu = false"#}
{# >#}
{# <v-icon>mdi-close-circle</v-icon>#}
{# </v-btn>#}
{# </v-list-item-action>#}
</v-list-item>
</v-list>
<v-list>
<v-list-item
key="website"
href="/"
>
<v-list-item-title>{{ _("See website") }}</v-list-item-title>
</v-list-item>
<v-list-item
key="logout"
href="/logout"
>
<v-list-item-title>{{ _("Logout") }}</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
</v-menu>
</v-app-bar>
<v-sheet
id="scrolling-techniques-5"
class="overflow-y-auto"
max-height="100vh"
min-height="100%"
style="background: none !important;"
>
{# <template v-slot:prepend>#}
{# <v-list>#}
{# <v-list-item>#}
{# <v-list-item-avatar>#}
{# <v-img src="https://randomuser.me/api/portraits/women/85.jpg"></v-img>#}
{# </v-list-item-avatar>#}
{# </v-list-item>#}
{##}
{# <v-list-item#}
{# link#}
{# two-line#}
{# >#}
{# <v-list-item-content>#}
{# <v-list-item-title class="title">Sandra Adams</v-list-item-title>#}
{# <v-list-item-subtitle>sandra_a88@gmail.com</v-list-item-subtitle>#}
{# </v-list-item-content>#}
{# <v-list-item-action>#}
{# <v-icon>mdi-menu-down</v-icon>#}
{# </v-list-item-action>#}
{# </v-list-item>#}
{# </v-list>#}
{# </template>#}
{##}
{# <v-divider></v-divider>#}
<template v-slot:prepend>
<v-list
nav
dense
>
<v-list-item link>
<v-list-item-icon>
<v-icon>mdi-folder</v-icon>
</v-list-item-icon>
<v-list-item-title>My Files</v-list-item-title>
</v-list-item>
<v-list-item link>
<v-list-item-icon>
<v-icon>mdi-account-multiple</v-icon>
</v-list-item-icon>
<v-list-item-title>Shared with me</v-list-item-title>
</v-list-item>
<v-list-item link>
<v-list-item-icon>
<v-icon>mdi-star</v-icon>
</v-list-item-icon>
<v-list-item-title>Starred</v-list-item-title>
</v-list-item>
</v-list>
</template>
</v-navigation-drawer>
<div style="height: 2500px; display: table-cell; vertical-align: top; padding-left: 10px; padding-top: 10px;">
Coucouuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu</div>
<v-container
style="padding-top: 37px; display: table; padding-left: 0; margin-left: 0; margin-right: 0; max-width: none;"
fill-height>
{# <div style="width: 260px; display: table-cell; vertical-align: top; height: 100%;">#}
<v-navigation-drawer
:expand-on-hover="windowSize.x < 1300"
permanent
{# absolute#}
style="z-index: 0; display: table-cell; vertical-align: top; height: 100%;"
>
{# <template v-slot:prepend>#}
{# <v-list>#}
{# <v-list-item>#}
{# <v-list-item-avatar>#}
{# <v-img src="https://randomuser.me/api/portraits/women/85.jpg"></v-img>#}
{# </v-list-item-avatar>#}
{# </v-list-item>#}
{##}
{# <v-list-item#}
{# link#}
{# two-line#}
{# >#}
{# <v-list-item-content>#}
{# <v-list-item-title class="title">Sandra Adams</v-list-item-title>#}
{# <v-list-item-subtitle>sandra_a88@gmail.com</v-list-item-subtitle>#}
{# </v-list-item-content>#}
{# <v-list-item-action>#}
{# <v-icon>mdi-menu-down</v-icon>#}
{# </v-list-item-action>#}
{# </v-list-item>#}
{# </v-list>#}
{# </template>#}
{##}
{# <v-divider></v-divider>#}
<template v-slot:prepend>
<v-list
nav
dense
>
<v-list-item link>
<v-list-item-icon>
<v-icon>mdi-folder</v-icon>
</v-list-item-icon>
<v-list-item-title>My Files</v-list-item-title>
</v-list-item>
<v-list-item link>
<v-list-item-icon>
<v-icon>mdi-account-multiple</v-icon>
</v-list-item-icon>
<v-list-item-title>Shared with me</v-list-item-title>
</v-list-item>
<v-list-item link>
<v-list-item-icon>
<v-icon>mdi-star</v-icon>
</v-list-item-icon>
<v-list-item-title>Starred</v-list-item-title>
</v-list-item>
</v-list>
</template>
</v-navigation-drawer>
<div style="display: table-cell; vertical-align: top; padding-left: 10px; padding-top: 10px;">
{% block bodycontent %}
{% endblock %}
</div>
</v-container>
</v-sheet>
</v-sheet>
{% endblock %}
\ No newline at end of file
{% extends "panel/basis.html" %}
{% block script %}
{{ super() }}
{% endblock %}
{% block bodycontent %}
Home page
{% endblock %}
\ No newline at end of file
{% extends "basis.html" %}
{% block appbody %}
<v-app-bar
absolute
color="#43a047"
shrink-on-scroll
prominent
src="https://picsum.photos/1920/1080?random"
{# fade-img-on-scroll#}
scroll-target="#scrolling-techniques-5"
scroll-threshold="500"
>
<v-app-bar
absolute
color="#43a047"
shrink-on-scroll
prominent
src="https://picsum.photos/1920/1080?random"
{# fade-img-on-scroll#}
scroll-target="#scrolling-techniques-5"
scroll-threshold="500"
>
<template v-slot:img="{ props }">
<v-img
v-bind="props"
gradient="to top right, rgba(55,236,186,.7), rgba(25,32,72,.7)"
></v-img>
<v-img
v-bind="props"
gradient="to top right, rgba(55,236,186,.7), rgba(25,32,72,.7)"
></v-img>
</template>
<v-app-bar-nav-icon></v-app-bar-nav-icon>
......@@ -24,38 +24,106 @@
<div class="flex-grow-1"></div>
<v-btn icon @click="showHideSearch()" id="btn-search">
<v-icon>mdi-magnify</v-icon>
</v-btn><v-text-field :color="searchFieldColor" v-show="search" ref="search" id="search" @keydown.esc="showHideSearch()"
@keydown.enter="launchSearch()" v-model="searchText"></v-text-field>
</v-app-bar>
<v-sheet
id="scrolling-techniques-5"
class="overflow-y-auto"
max-height="100vh"
min-height="100%"
style="background: none"
>
<v-container style="padding-top: 117px; display: table; padding-left: 0; padding-right: 0; margin-left: 0; margin-right: 0; max-width: none;" fill-height>
{# <div style="width: 260px; display: table-cell; vertical-align: top; height: 100%;">#}
<v-btn icon @click="showHideSearch()" id="btn-search" v-if="show_search">
<v-icon>mdi-magnify</v-icon>
</v-btn>
<v-text-field :color="searchFieldColor" v-show="search" ref="search" id="search" @keydown.esc="showHideSearch()"
@keydown.enter="launchSearch()" v-model="searchText"></v-text-field>
<v-menu v-if="logged"
v-model="menu"
top
right
transition="scale-transition"
origin="top right"
>
<template v-slot:activator="{ on }">
<v-chip
pill
v-on="on"
style="margin-top: 5px;"
>
<v-avatar left>
<v-img :src="avatar_src"></v-img>
</v-avatar>
<b style="padding-left: 5px; padding-right: 5px;">{{ name }}</b>
</v-chip>
</template>
<v-card width="300">
<v-list dark>
<v-list-item>
<v-list-item-avatar>
<v-img :src="avatar_src"></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>(( name ))</v-list-item-title>
<v-list-item-subtitle>((user_role_name ))</v-list-item-subtitle>
</v-list-item-content>
{# <v-list-item-action>#}
{# <v-btn#}
{# icon#}
{# @click="menu = false"#}
{# >#}
{# <v-icon>mdi-close-circle</v-icon>#}
{# </v-btn>#}
{# </v-list-item-action>#}
</v-list-item>
</v-list>
<v-list>
<v-list-item
key="panel"
href="/panel"
>
<v-list-item-title>{{ _("Panel") }}</v-list-item-title>
</v-list-item>
<v-list-item
key="logout"
href="/logout"
>
<v-list-item-title>{{ _("Logout") }}</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
</v-menu>
<v-tooltip bottom v-else>
<template v-slot:activator="{ on }">
<v-chip pill v-on="on" style="margin-top: 5px;" href="/login">
<v-icon>mdi-account</v-icon>
</v-chip>
</template>
<span>{{ _("Login") }}</span>
</v-tooltip>
</v-app-bar>
<v-sheet
id="scrolling-techniques-5"
class="overflow-y-auto"
max-height="100vh"
min-height="100%"
style="background: none"
>
<v-container
style="padding-top: 117px; display: table; padding-left: 0; padding-right: 0; margin-left: 0; margin-right: 0; max-width: none;"
fill-height>
{# <div style="width: 260px; display: table-cell; vertical-align: top; height: 100%;">#}
<div id="loading" v-show="loadings > 0">
<div class="loader"></div>
</div>
<v-alert v-model="show_alert" :type="type_alert" style="margin-top: 15px; position: fixed; width: 100%; z-index: 10;" dismissible>
(( message_alert ))
<v-alert v-model="show_alert" :type="type_alert"
style="margin-top: 15px; position: fixed; width: 100%; z-index: 10;" dismissible>
(( message_alert ))
</v-alert>
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
{% set message = message.split("|") %}
<v-alert type="{{ message[0] }}" style="margin-top: 15px; position: fixed; width: 100%; z-index: 10;" dismissible>
{{ message[1] }}
</v-alert>
{% endfor %}
{% endif %}
{% if messages %}
{% for message in messages %}
{% set message = message.split("|") %}
<v-alert type="{{ message[0] }}"
style="margin-top: 15px; position: fixed; width: 100%; z-index: 10;" dismissible>
{{ message[1] }}
</v-alert>
{% endfor %}
{% endif %}
{% endwith %}
{% block bodycontent %}
{% endblock %}
</v-container>
</v-sheet>
</v-sheet>
{% endblock %}
\ No newline at end of file
......@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2019-09-14 16:55+0200\n"
"PO-Revision-Date: 2019-09-14 16:56+0200\n"
"POT-Creation-Date: 2019-09-14 18:34+0200\n"
"PO-Revision-Date: 2019-09-14 18:34+0200\n"
"Last-Translator: \n"
"Language: fr\n"
"Language-Team: fr <LL@li.org>\n"
......@@ -19,19 +19,19 @@ msgstr ""
"Generated-By: Babel 2.7.0\n"
"X-Generator: Poedit 2.0.6\n"
#: app.py:62 view/panel.py:21
#: app.py:68 templates/web/basis.html:48 view/panel.py:22
msgid "Panel"
msgstr "Panel"
#: app.py:74
#: app.py:80 templates/web/basis.html:65
msgid "Login"
msgstr "Connexion"
msgstr "Se connecter"
#: app.py:87
#: app.py:93
msgid "Bad mail or password"