First version of the interface #1

Merged
alexandre merged 10 commits from base into master 2021-11-29 05:41:53 +01:00
4 changed files with 106 additions and 40 deletions
Showing only changes of commit 442f920681 - Show all commits

View File

@@ -7,29 +7,48 @@ from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, \
SubmitField
from wtforms.validators import ValidationError, DataRequired, \
Email, EqualTo, Length
Email, EqualTo, Length, Regexp
from werkzeug.security import check_password_hash, generate_password_hash
import re
bp = Blueprint('reset', __name__, url_prefix='/reset')
class ResetPasswordForm(FlaskForm):
username = StringField(label=('Username'),
# Minimal password length
minlength = 9
# Form
username = StringField(label=('Login'),
validators=[DataRequired(),
Length(max=64)])
currentpassword = PasswordField(label=('Current password'),
validators=[DataRequired()])
newpassword = PasswordField(label=('New password'),
validators=[DataRequired(),
Length(min=8, message='Password should be at least %(min)d characters long')],
render_kw={"onkeyup": "validate_form()"})
Length(min=minlength, message='Password should be at least %(min)d characters long'),
Regexp("^(?=.*[a-z])", message="Password must have a lowercase character"),
Regexp("^(?=.*[A-Z])", message="Password must have an uppercase character"),
Regexp("^(?=.*\\d)", message="Password must contain a number"),
#Regexp(
# "(?=.*[@$!%*#?&])", message="Password must contain a special character"
#),],
],
render_kw={"onkeyup": f"validate_form({minlength})"})
confirm_password = PasswordField(
label=('Confirm Password'),
validators=[DataRequired(message='* Required'),
EqualTo('newpassword', message='Both password fields must be equal!')],
render_kw={"onkeyup": "validate_confirm()"})
render_kw={"onkeyup": f"validate_confirm({minlength})"})
submit = SubmitField(label=('Change my password'), render_kw={"onclick": "validate_form()"})
submit = SubmitField(label=('Change my password'), render_kw={"onclick": f"validate_form({minlength})"})
# Validators
def validate_username(self, username):
excluded_chars = " *?!'^+%&/()=}][{$#;\\\""
for char in self.username.data:
if char in excluded_chars:
raise ValidationError(
f"Character {char} is not allowed in a login.")
@bp.route('/', methods=('GET', 'POST'))
def reset():

View File

@@ -51,17 +51,36 @@ a:hover>span {
font-size: 32px;
}
#confirm-msg,
#password-msg {
color: #d4d4d4;
font-size: small;
transition: color 225ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
#password-msg li {
list-style: none;
content: ""
}
#password-msg li::before {
content: "☑ ";
}
.errorinput {
border-color: #f44246 !important;
}
#confirm-msg,
#password-msg {
color: #f44246;
opacity: 0;
transition: opacity 225ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
.errormsg {
color: #f44246 !important;
}
li.errormsg::before {
content: "☒ " !important;
}
.errorinput:focus {
box-shadow: 0 0 0 .10rem rgba(244, 66, 70, 0.50) !important;
-webkit-box-shadow: 0 0 0 .10rem rgba(244, 66, 70, 0.50) !important;
@@ -77,8 +96,3 @@ a:hover>span {
background: #4e4e4e;
border-radius: .50rem;
}
.fade {
opacity: 1 !important;
transition: opacity 300ms cubic-bezier(0.55, 0.085, 0.68, 0.53);
}

View File

@@ -1,5 +1,5 @@
function validate_form() {
var pass = validate_password();
function validate_form(minlength) {
var pass = validate_password(minlength);
return validate_confirm() && pass;
}
@@ -10,28 +10,55 @@ function validate_confirm() {
if (password.value != confirm.value) {
confirm.classList.add("errorinput");
document.getElementById("confirm-msg").classList.add("fade");
document.getElementById("confirm-msg").classList.add("errormsg");
return false;
}
confirm.classList.remove("errorinput");
document.getElementById("confirm-msg").classList.remove("fade");
document.getElementById("confirm-msg").classList.remove("errormsg");
return true;
}
function validate_password() {
function validate_password(minlength) {
// Did the checks pass ?
var status = true;
// Target element
var password = document.getElementById("newpassword");
var reg = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}/;
if (reg.test(password.value) != true) {
password.classList.add("errorinput");
document.getElementById("password-msg").classList.add("fade");
return false;
// Check the length
if (password.value.length < minlength)
{
status = false;
document.getElementById("minlen").classList.add("errormsg");
}
else
document.getElementById("minlen").classList.remove("errormsg");
// Look for a digit
if (/.*\d/.test(password.value) != true) {
status = false;
document.getElementById("digit").classList.add("errormsg");
}
else
document.getElementById("digit").classList.remove("errormsg");
// Look for a lowercase char
if (/.*[a-z]/.test(password.value) != true) {
status = false;
document.getElementById("lower").classList.add("errormsg");
}
else
document.getElementById("lower").classList.remove("errormsg");
// Look for an uppercase char
if (/.*[A-Z]/.test(password.value) != true) {
status = false;
document.getElementById("upper").classList.add("errormsg");
}
else
document.getElementById("upper").classList.remove("errormsg");
// Change the color of the inputbox
if (status == false)
password.classList.add("errorinput");
else
password.classList.remove("errorinput");
document.getElementById("password-msg").classList.remove("fade");
return true;
return status;
}

View File

@@ -1,7 +1,7 @@
{% extends 'base.html' %}
{% block main_block %}
<div class="row col" id="reset-form">
<div class="row col-md" id="reset-form">
{% for field, errors in form.errors.items() %}
{{ ', '.join(errors) }}
{% endfor %}
@@ -17,20 +17,26 @@
</div>
<div class="form-group">
{{ form.newpassword.label }}
<span id="password-msg">
The new password should contain at least : 8 characters, one numeric digit, one lowercase and one uppercase characters.
</span>
<div id="password-msg">
The new password should contain at least :
<ul>
<li id="minlen">{{ form.minlength }} characters</li>
<li id="digit">1 numeric digit [0-9]</li>
<li id="lower">1 lowercase character [a-z]</li>
<li id="upper">1 uppercase character [A-Z]</li>
</ul>
</div>
{{ form.newpassword(class="form-control") }}
</div>
<div class="form-group">
{{ form.confirm_password.label }}
<span id="confirm-msg">
Passwords should match
</span>
<div id="confirm-msg">
Passwords must match
</div>
{{ form.confirm_password(class="form-control") }}
</div>
<br>
<div class="form-group" style="text-align: center; margin-bottom: 0.40 em">
<div class="form-group" style="text-align: center; margin-bottom: 0.40em">
{{ form.submit(class="btn btn-primary")}}
</div>
</form>