Merge branch 'feature/server-side-render' into feature/server-side-render-devices

This commit is contained in:
Santiago L 2022-01-04 12:00:15 +01:00
commit c2a058bf51
13 changed files with 91 additions and 188 deletions

View File

@ -66,6 +66,7 @@ jobs:
- name: Run Tests
run: |
export SECRET_KEY=`python3 -c 'import secrets; print(secrets.token_hex())'`
source env/bin/activate
coverage run --source='ereuse_devicehub' env/bin/pytest -m mvp --maxfail=5 tests/
coverage report --include='ereuse_devicehub/*'

View File

@ -1,15 +1,14 @@
from flask_wtf import FlaskForm
from werkzeug.security import generate_password_hash
from wtforms import EmailField, PasswordField, validators
from wtforms import BooleanField, EmailField, PasswordField, validators
from ereuse_devicehub.resources.user.models import User
class LoginForm(FlaskForm):
email = EmailField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('Password', [
validators.DataRequired(),
])
password = PasswordField('Password', [validators.DataRequired()])
remember = BooleanField('Remember me')
error_messages = {
'invalid_login': (

View File

@ -71,6 +71,12 @@ class User(UserMixin, Thing):
"""Alias because flask-login expects `is_active` attribute"""
return self.active
@property
def get_full_name(self):
# TODO(@slamora) create first_name & last_name fields and use
# them to generate user full name
return self.email
def check_password(self, password):
# take advantage of SQL Alchemy PasswordType to verify password
return self.password == password

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 610 B

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1,47 @@
<?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"
id="svg8"
version="1.1"
viewBox="0 0 59.641495 19.325608"
height="19.325607mm"
width="59.641495mm">
<defs
id="defs2" />
<metadata
id="metadata5">
<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>
<g
transform="translate(-149.20084,-143.42372)"
id="layer1">
<text
id="text823"
y="158.73648"
x="80.130806"
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="font-size:22.57777786px;stroke-width:0.26458332"
id="tspan821"
y="158.73648"
x="147.32671"><tspan
id="tspan819"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.57777786px;font-family:Calibri;-inkscape-font-specification:Calibri;fill:#993366;fill-opacity:1;stroke-width:0.26458332"
y="158.73648"
x="147.32671"><tspan
id="tspan825"
style="fill:#0a0406;fill-opacity:1">USO</tspan>dy</tspan></tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -5,7 +5,7 @@
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Users / Profile - NiceAdmin Bootstrap Template</title>
<title>{% block page_title %}{% endblock %} - USOdy</title>
<meta content="" name="description">
<meta content="" name="keywords">

View File

@ -5,8 +5,7 @@
<div class="d-flex align-items-center justify-content-between">
<a href="index.html" class="logo d-flex align-items-center">
<img src="{{ url_for('static', filename='img/logo.png') }}" alt="">
<span class="d-none d-lg-block">NiceAdmin</span>
<img src="{{ url_for('static', filename='img/usody-logo-black.svg') }}" alt="">
</a>
<i class="bi bi-list toggle-sidebar-btn"></i>
</div><!-- End Logo -->
@ -27,165 +26,23 @@
</a>
</li><!-- End Search Icon-->
<li class="nav-item dropdown">
<a class="nav-link nav-icon" href="#" data-bs-toggle="dropdown">
<i class="bi bi-bell"></i>
<span class="badge bg-primary badge-number">4</span>
</a><!-- End Notification Icon -->
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow notifications">
<li class="dropdown-header">
You have 4 new notifications
<a href="#"><span class="badge rounded-pill bg-primary p-2 ms-2">View all</span></a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="bi bi-exclamation-circle text-warning"></i>
<div>
<h4>Lorem Ipsum</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>30 min. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="bi bi-x-circle text-danger"></i>
<div>
<h4>Atque rerum nesciunt</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>1 hr. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="bi bi-check-circle text-success"></i>
<div>
<h4>Sit rerum fuga</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>2 hrs. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="notification-item">
<i class="bi bi-info-circle text-primary"></i>
<div>
<h4>Dicta reprehenderit</h4>
<p>Quae dolorem earum veritatis oditseno</p>
<p>4 hrs. ago</p>
</div>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-footer">
<a href="#">Show all notifications</a>
</li>
</ul><!-- End Notification Dropdown Items -->
</li><!-- End Notification Nav -->
<li class="nav-item dropdown">
<a class="nav-link nav-icon" href="#" data-bs-toggle="dropdown">
<i class="bi bi-chat-left-text"></i>
<span class="badge bg-success badge-number">3</span>
</a><!-- End Messages Icon -->
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow messages">
<li class="dropdown-header">
You have 3 new messages
<a href="#"><span class="badge rounded-pill bg-primary p-2 ms-2">View all</span></a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="message-item">
<a href="#">
<img src="{{ url_for('static', filename='img/messages-1.jpg') }}" alt="" class="rounded-circle">
<div>
<h4>Maria Hudson</h4>
<p>Velit asperiores et ducimus soluta repudiandae labore officia est ut...</p>
<p>4 hrs. ago</p>
</div>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="message-item">
<a href="#">
<img src="{{ url_for('static', filename='img/messages-2.jpg') }}" alt="" class="rounded-circle">
<div>
<h4>Anna Nelson</h4>
<p>Velit asperiores et ducimus soluta repudiandae labore officia est ut...</p>
<p>6 hrs. ago</p>
</div>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="message-item">
<a href="#">
<img src="{{ url_for('static', filename='img/messages-3.jpg') }}" alt="" class="rounded-circle">
<div>
<h4>David Muldon</h4>
<p>Velit asperiores et ducimus soluta repudiandae labore officia est ut...</p>
<p>8 hrs. ago</p>
</div>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-footer">
<a href="#">Show all messages</a>
</li>
</ul><!-- End Messages Dropdown Items -->
</li><!-- End Messages Nav -->
<li class="nav-item dropdown pe-3">
<a class="nav-link nav-profile d-flex align-items-center pe-0" href="#" data-bs-toggle="dropdown">
<img src="{{ url_for('static', filename='img/profile-img.jpg') }}" alt="Profile" class="rounded-circle">
<span class="d-none d-md-block dropdown-toggle ps-2">K. Anderson</span>
<i class="bi bi-person-circle" style="font-size: 36px;"></i>
<span class="d-none d-md-block dropdown-toggle ps-2">{{ current_user.email }}</span>
</a><!-- End Profile Iamge Icon -->
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow profile">
<li class="dropdown-header">
<h6>Kevin Anderson</h6>
<span>Web Designer</span>
<h6>{{ current_user.get_full_name }}</h6>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item d-flex align-items-center" href="users-profile.html">
<a class="dropdown-item d-flex align-items-center" href="{{ url_for('core.user-profile') }}">
<i class="bi bi-person"></i>
<span>My Profile</span>
</a>
@ -194,16 +51,6 @@
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item d-flex align-items-center" href="users-profile.html">
<i class="bi bi-gear"></i>
<span>Account Settings</span>
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item d-flex align-items-center" href="pages-faq.html">
<i class="bi bi-question-circle"></i>
@ -215,7 +62,7 @@
</li>
<li>
<a class="dropdown-item d-flex align-items-center" href="#">
<a class="dropdown-item d-flex align-items-center" href="{{ url_for('core.logout') }}">
<i class="bi bi-box-arrow-right"></i>
<span>Sign Out</span>
</a>
@ -316,7 +163,7 @@
</li><!-- End Labels Page Nav -->
<li class="nav-item">
<a class="nav-link collapsed" href="#TODO">
<a class="nav-link collapsed" href="{{ url_for('Document.StampsView') }}">
<i class="bi bi-pin-map-fill"></i>
<span>Stamp</span>
</a>

View File

@ -1,4 +1,7 @@
{% extends "ereuse_devicehub/base.html" %}
{% block page_title %}Login{% endblock %}
{% block body %}
<main>
<div class="container">
@ -9,9 +12,8 @@
<div class="col-lg-4 col-md-6 d-flex flex-column align-items-center justify-content-center">
<div class="d-flex justify-content-center py-4">
<a href="index.html" class="logo d-flex align-items-center w-auto">
<img src="{{ url_for('static', filename='img/logo.png') }}" alt="">
<span class="d-none d-lg-block">NiceAdmin</span>
<a href="{{ url_for('core.login') }}" class="logo d-flex align-items-center w-auto">
<img src="{{ url_for('static', filename='img/usody-logo-black.svg') }}" alt="">
</a>
</div><!-- End Logo -->
@ -35,12 +37,9 @@
{{ form.csrf_token }}
<div class="col-12">
<label for="yourUsername" class="form-label">Email</label>
<div class="input-group has-validation">
<span class="input-group-text" id="inputGroupPrepend">@</span>
<input type="text" name="email" class="form-control" id="yourUsername" required value="{{ form.email.data|default('', true) }}">
<div class="invalid-feedback">Please enter your username.</div>
</div>
<label for="yourEmail" class="form-label">Email</label>
<input type="email" name="email" class="form-control" id="yourEmail" required value="{{ form.email.data|default('', true) }}">
<div class="invalid-feedback">Please enter your email.</div>
</div>
<div class="col-12">
@ -51,7 +50,7 @@
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" value="true" id="rememberMe">
<input class="form-check-input" type="checkbox" name="remember" {% if form.remember.data %}checked{% endif %} id="rememberMe">
<label class="form-check-label" for="rememberMe">Remember me</label>
</div>
</div>

View File

@ -1,4 +1,7 @@
{% extends "ereuse_devicehub/base_site.html" %}
{% block page_title %}Your Profile{% endblock %}
{% block main %}
<div class="pagetitle">
@ -18,16 +21,8 @@
<div class="card">
<div class="card-body profile-card pt-4 d-flex flex-column align-items-center">
<img src="{{ url_for('static', filename='img/profile-img.jpg') }}" alt="Profile" class="rounded-circle">
<h2>Kevin Anderson</h2>
<h3>Web Designer</h3>
<div class="social-links mt-2">
<a href="#" class="twitter"><i class="bi bi-twitter"></i></a>
<a href="#" class="facebook"><i class="bi bi-facebook"></i></a>
<a href="#" class="instagram"><i class="bi bi-instagram"></i></a>
<a href="#" class="linkedin"><i class="bi bi-linkedin"></i></a>
</div>
<i class="bi bi-person-circle" style="font-size: 76px;"></i>
<h2>{{ current_user.get_full_name }}</h2>
</div>
</div>

View File

@ -1,7 +1,7 @@
import flask
from flask import Blueprint
from flask.views import View
from flask_login import login_required, login_user
from flask_login import current_user, login_required, login_user, logout_user
from ereuse_devicehub.forms import LoginForm
from ereuse_devicehub.resources.user.models import User
@ -20,7 +20,7 @@ class LoginView(View):
# Login and validate the user.
# user should be an instance of your `User` class
user = User.query.filter_by(email=form.email.data).first()
login_user(user)
login_user(user, remember=form.remember.data)
next_url = flask.request.args.get('next')
# is_safe_url should check if the url is safe for redirects.
@ -32,14 +32,23 @@ class LoginView(View):
return flask.render_template('ereuse_devicehub/user_login.html', form=form)
class LogoutView(View):
def dispatch_request(self):
logout_user()
return flask.redirect(flask.url_for('core.login'))
class UserProfileView(View):
decorators = [login_required]
template_name = 'ereuse_devicehub/user_profile.html'
def dispatch_request(self):
context = {}
context = {
'current_user': current_user,
}
return flask.render_template(self.template_name, **context)
core.add_url_rule('/login/', view_func=LoginView.as_view('login'))
core.add_url_rule('/logout/', view_func=LogoutView.as_view('logout'))
core.add_url_rule('/profile/', view_func=UserProfileView.as_view('user-profile'))