diff --git a/app/forms/account.py b/app/forms/account.py index 8e7671e..d4abf6b 100644 --- a/app/forms/account.py +++ b/app/forms/account.py @@ -33,10 +33,20 @@ class DeleteAccountForm(FlaskForm): class AdminUpdateAccountForm(FlaskForm): - username = StringField('Pseudonyme', validators=[Optional(), vd.name_valid]) - avatar = FileField('Avatar', validators=[Optional(), vd.avatar]) - email = StringField('Adresse email', validators=[Optional(), Email(), vd.email]) - password = PasswordField('Mot de passe', validators=[Optional(), vd.password]) + username = StringField('Pseudonyme', + validators=[Optional(), vd.name_valid]) + avatar = FileField('Avatar', + validators=[Optional(), vd.avatar]) + email = StringField('Adresse email', + validators=[Optional(), Email(), vd.email]) + email_validate = BooleanField("""Envoyer un email de validation à la + nouvelle adresse""", + description="""Si décoché, l'utilisateur devra demander explicitement + un email de validation, ou faire valider son adresse email par un + administrateur.""") + password = PasswordField('Mot de passe', + description="L'ancien mot de passe ne pourra pas être récupéré !", + validators=[Optional(), vd.password]) xp = DecimalField('XP', validators=[Optional()]) innovation = DecimalField('Innovation', validators=[Optional()]) birthday = DateField('Anniversaire', validators=[Optional()]) diff --git a/app/models/users.py b/app/models/users.py index 91d90b9..745518f 100644 --- a/app/models/users.py +++ b/app/models/users.py @@ -9,6 +9,7 @@ from config import V5Config import werkzeug.security import app import re +import math # User: Website user that performs actions on the content class User(UserMixin, db.Model): @@ -103,6 +104,12 @@ class Member(User, db.Model): def avatar(self): return 'avatars/' + str(self.id) + '.png' + @property + def level(self): + xp = self.xp + 2 * self.innovation + level = math.asinh(xp / 1000) * (100 / math.asinh(10)) + return int(level), int(level * 100) % 100 + # Groups and related privileges groups = db.relationship('Group', secondary=GroupMember, back_populates='members') diff --git a/app/routes/admin.py b/app/routes/admin.py index 27afeb9..230f058 100644 --- a/app/routes/admin.py +++ b/app/routes/admin.py @@ -62,6 +62,7 @@ def adm_groups(): db.session.add(m) m = Member('GLaDOS', 'glados@aperture.science', 'v5-forever') + m.xp = 1337 addgroup(m, "Robot") db.session.add(m) db.session.commit() @@ -111,7 +112,7 @@ def adm_edit_account(user_id): else: flash('Erreur lors de la modification', 'error') - return render('admin/edit_account.html', user=user, form=form, styles=['-css/form.css']) + return render('admin/edit_account.html', user=user, form=form) @app.route('/admin/edit-account//delete', methods=['GET', 'POST']) @priv_required('delete-account') diff --git a/app/routes/users.py b/app/routes/users.py index b9165b5..88fcbd0 100644 --- a/app/routes/users.py +++ b/app/routes/users.py @@ -7,14 +7,10 @@ from app.utils.render import render @app.route('/user/') def user(username): - user = Member.query.filter_by(name=username).first() - if not user: - abort(404) - return render('user.html', user=user) + member = Member.query.filter_by(name=username).first_or_404() + return render('user.html', member=member) @app.route('/user/id/') def user_by_id(user_id): - user = Member.query.filter_by(id=user_id).first() - if not user: - abort(404) - return redirect(url_for('user', username=user.name)) + member = Member.query.filter_by(id=user_id).first_or_404() + return redirect(url_for('user', username=member.name)) diff --git a/app/static/css/form.css b/app/static/css/form.css index f7bcb8d..b28c973 100644 --- a/app/static/css/form.css +++ b/app/static/css/form.css @@ -8,12 +8,15 @@ } .form form > div:not(:last-child) { - margin-bottom: 15px; + margin-bottom: 16px; } .form form label { display: inline-block; - margin-bottom: 5px; + margin-bottom: 4px; +} +.form label + .desc { + margin: 0 0 4px 0; } .form input { @@ -39,8 +42,8 @@ .form input[type='password']:focus, .form input[type='search']:focus, .form textarea:focus { - border-color: #91bfef; - box-shadow: 0 0 0 3px rgba(87, 143, 228, 0.4); + border-color: #7cade0; + box-shadow: 0 0 0 3px rgba(87, 143, 228, 0.5); } .form textarea { @@ -57,3 +60,8 @@ font-weight: 400; margin-top: 5px; } + +.form .desc { + font-size: 80%; + color: gray; +} diff --git a/app/static/css/global.css b/app/static/css/global.css index 3cc059a..5aba4db 100644 --- a/app/static/css/global.css +++ b/app/static/css/global.css @@ -78,6 +78,67 @@ input[type="submit"]:hover, text-decoration: none; } +/* Profile summaries */ + +.profile { + display: flex; + align-items: center; +} +.profile-avatar { + width: 128px; + height: 128px; + margin-right: 16px; +} +.profile-name { + font-weight: bold; +} +.profile-title { + margin-bottom: 8px; +} +.profile-points { + font-size: 11px; +} +.profile-points span { + color: gray; +} +.profile-points-small { + display: none; +} +.profile-xp { + height: 10px; + min-width: 96px; + background: #e0e0e0; + border: 1px solid #c0c0c0; +} +.profile-xp div { + height: 10px; + background: #f85555; + border: 1px solid #d03333; + margin: -1px; +} + +@media screen and (max-width: 1499px) { + .profile-avatar { + width: 96px; + height: 96px; + } + .profile-xp { + height: 8px; + min-width: 64px; + } + .profile-xp div { + height: 8px; + } +} +@media screen and (max-width: 1199px) { + .profile-points { + display: none; + } + .profile-points-small { + display: unset; + } +} + /* Bootstrap-style rules */ diff --git a/app/static/css/navbar.css b/app/static/css/navbar.css index 51020ac..2d333ed 100644 --- a/app/static/css/navbar.css +++ b/app/static/css/navbar.css @@ -189,15 +189,15 @@ nav a:focus { } #menu form input[type="text"], #menu form input[type="password"] { - margin: 3px 0 8px 0; padding: 5px 2%; + margin: 8px 0; padding: 5px 2%; font-size: 14px; color: inherit; - border-color: #141719; + border: none; border-color: #141719; } #menu form input[type="text"]:focus, #menu form input[type="password"]:focus { background: #ffffff; - box-shadow: 0 0 0 3px rgba(87, 143, 228, 0.6); - border-color: #2d4b5f; + box-shadow: 0 0 0 4px rgba(87, 143, 228, 0.65); + border-color: #325871; } #menu form input[type="submit"] { width: 100%; diff --git a/app/templates/admin/edit_account.html b/app/templates/admin/edit_account.html index 0d64b36..b55c6f7 100644 --- a/app/templates/admin/edit_account.html +++ b/app/templates/admin/edit_account.html @@ -1,97 +1,100 @@ {% extends "base/base.html" %} {% block title %} -Panneau d'administration »

Édition du compte de '{{ user.name }}'

+Panneau d'administration »

Édition du compte de {{ user.name }}

{% endblock %} {% block content %}
+ Visiter la page de profil de {{ user.name }}
{{ form.hidden_tag() }} -
- Général -
- {{ form.avatar.label }} -
- - {{ form.avatar }} -
-
+

Participation

+ +
+ {{ form.avatar.label }}
- {{ form.username.label }} - {{ form.username(placeholder=user.name) }} - {% for error in form.username.errors %} - {{ error }} - {% endfor %} + + {{ form.avatar }}
-
- {{ form.email.label }} - {{ form.email(placeholder=user.email) }} - {% for error in form.email.errors %} - {{ error }} - {% endfor %} -
-
- {{ form.password.label }} - {{ form.password(placeholder='************') }} - {% for error in form.password.errors %} - {{ error }} - {% endfor %} -
-
{{ form.submit(class_="bg-green") }}
-
-
- Participation -
- {{ form.xp.label }} - {{ form.xp(placeholder=user.xp) }} - {% for error in form.xp.errors %} - {{ error }} - {% endfor %} -
-
- {{ form.innovation.label }} - {{ form.innovation(placeholder=user.innovation) }} - {% for error in form.innovation.errors %} - {{ error }} - {% endfor %} -
-
-
- À propos -
- {{ form.birthday.label }} - {{ form.birthday(value=user.birthday) }} - {% for error in form.birthday.errors %} - {{ error }} - {% endfor %} -
-
- {{ form.signature.label }} - - {% for error in form.signature.errors %} - {{ error }} - {% endfor %} -
-
- {{ form.biography.label }} - - {% for error in form.biography.errors %} - {{ error }} - {% endfor %} -
-
-
- Préférences -
- {{ form.newsletter.label }} - {{ form.newsletter(checked=user.newsletter) }} -
{{ form.newsletter.description }}
- {% for error in form.newsletter.errors %} - {{ error }} - {% endfor %} -
-
+ + +
+ {{ form.username.label }} + {{ form.username(placeholder=user.name) }} + {% for error in form.username.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.email.label }} + {{ form.email(placeholder=user.email) }} + {% for error in form.email.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.email_validate.label }} + {{ form.email_validate(checked=True) }} +
{{ form.email_validate.description }}
+
+
+ {{ form.password.label }} +
{{ form.password.description }}
+ {{ form.password(placeholder='************') }} + {% for error in form.password.errors %} + {{ error }} + {% endfor %} +
+ +

Participation

+
+ {{ form.xp.label }} + {{ form.xp(placeholder=user.xp) }} + {% for error in form.xp.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.innovation.label }} + {{ form.innovation(placeholder=user.innovation) }} + {% for error in form.innovation.errors %} + {{ error }} + {% endfor %} +
+ +

À propos

+
+ {{ form.birthday.label }} + {{ form.birthday(value=user.birthday) }} + {% for error in form.birthday.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.signature.label }} + + {% for error in form.signature.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.biography.label }} + + {% for error in form.biography.errors %} + {{ error }} + {% endfor %} +
+ +

Préférences

+
+ {{ form.newsletter.label }} + {{ form.newsletter(checked=user.newsletter) }} +
{{ form.newsletter.description }}
+ {% for error in form.newsletter.errors %} + {{ error }} + {% endfor %} +
{{ form.submit(class_="bg-green") }}
diff --git a/app/templates/user.html b/app/templates/user.html index e1cc82a..264def3 100644 --- a/app/templates/user.html +++ b/app/templates/user.html @@ -1,14 +1,12 @@ {% extends "base/base.html" %} +{% import "widgets/user.html" as widget_member %} {% block title %} -

Profil de '{{ user.name }}'

+

Profil de {{ member.name }}

{% endblock %} {% block content %}
-
- {{ user.name }} - {{ user.name }} -
+ {{ widget_member.profile(member) }}
{% endblock %} diff --git a/app/templates/widgets/member.html b/app/templates/widgets/member.html new file mode 100644 index 0000000..aaeb070 --- /dev/null +++ b/app/templates/widgets/member.html @@ -0,0 +1,12 @@ +{% macro profile(member) %} +
+ Avatar de {{ member.name }} +
+ +
Membre
+
Niveau {{ member.level[0] }} ({{ member.xp }})
+
N{{ member.level[0] }} ({{ member.xp }})
+
+
+
+{% endmacro %} diff --git a/app/templates/widgets/user.html b/app/templates/widgets/user.html new file mode 100644 index 0000000..1ba38c3 --- /dev/null +++ b/app/templates/widgets/user.html @@ -0,0 +1,12 @@ +{% macro profile(member) %} +
+ Avatar de {{ member.name }} +
+
{{ member.name }}
+
Membre
+
Niveau {{ member.level[0] }} ({{ member.xp }})
+
N{{ member.level[0] }} ({{ member.xp }})
+
+
+
+{% endmacro %} diff --git a/app/utils/render.py b/app/utils/render.py index 263be80..62c06dd 100644 --- a/app/utils/render.py +++ b/app/utils/render.py @@ -2,7 +2,7 @@ from flask import render_template from app.forms.login import LoginForm from app.forms.search import SearchForm -def render(*args, styles=None, **kwargs): +def render(*args, styles=[], **kwargs): # TODO: debugguer cette merde : au logout, ça foire # if current_user.is_authenticated: # login_form = LoginForm() @@ -33,4 +33,4 @@ def render(*args, styles=None, **kwargs): login_form = LoginForm() search_form = SearchForm() return render_template(*args, **kwargs, - login_form=login_form, search_form=search_form, styles=styles_) \ No newline at end of file + login_form=login_form, search_form=search_form, styles=styles_)