Add public name customization and small style adjustments

This commit is contained in:
Guillaume Bertholon 2020-12-20 01:10:02 +01:00
parent f401c66f97
commit 0d838cafee
20 changed files with 176 additions and 162 deletions

View file

@ -81,6 +81,8 @@ AUTH_PASSWORD_VALIDATORS = [
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
]
LOGIN_URL = "gestiojeux_auth:login"
# Use markdown extensions
MARKDOWNX_MARKDOWN_EXTENSIONS = [
"markdown.extensions.extra",

24
gestiojeux_auth/forms.py Normal file
View file

@ -0,0 +1,24 @@
from django.forms import ModelForm, ValidationError
from django.contrib.auth.models import User
class AccountSettingsForm(ModelForm):
class Meta:
model = User
fields = ["first_name"]
labels = {"first_name": "Nom ou pseudo"}
help_texts = {
"first_name": "Ce nom sera utilisé pour toutes vos interactions publiques sur GestioJeux. Si laissé vide, votre login sera utilisé à la place."
}
def clean_first_name(self):
""" Check there is no conflict that could lead to imprersonation """
public_name = self.cleaned_data["first_name"]
public_name = public_name.strip()
if public_name == self.instance.first_name or public_name == "":
return public_name
if User.objects.filter(first_name=public_name).count() > 0:
raise ValidationError("Un autre compte utilise déjà ce nom ou ce pseudo.")
if User.objects.filter(username=public_name).count() > 0:
raise ValidationError("Ce nom est déjà le login de quelqu'un.")
return public_name

View file

@ -0,0 +1,20 @@
{% extends "small_page.html" %}
{% block "content" %}
<h1>Paramètres du compte</h1>
<p>Vous êtes connecté en tant que <tt>{{ request.user.username }}</tt></p>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Enregistrer</button>
</form>
{% if request.user.password and request.user.has_usable_password %}
<hr/>
<a href="{% url "gestiojeux_auth:change_password" %}">Changer mon mot de passe</a>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,12 @@
{% extends "small_page.html" %}
{% block "content" %}
<h1>Changement de mot de passe</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Changer de mot de passe</button>
</form>
{% endblock %}

View file

@ -3,7 +3,7 @@
{% block "content" %}
<h1>Connexion par mot de passe</h1>
<form method="post" action="{% url "gestiojeux_auth:password_login" %}?next={{ next|urlencode }}">
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Connexion</button>

View file

@ -1,6 +1,6 @@
from django.urls import include, path
import django.contrib.auth.views as dj_auth_views
from .views import LoginView, LogoutView
from .views import LoginView, LogoutView, PasswordChangeView, AccountSettingsView
import django_cas_ng.views
app_name = "gestiojeux_auth"
@ -20,6 +20,8 @@ accounts_patterns = [
path("login/", LoginView.as_view(), name="login"),
path("logout/", LogoutView.as_view(), name="logout"),
path("password_login/", dj_auth_views.LoginView.as_view(), name="password_login"),
path("change_password/", PasswordChangeView.as_view(), name="change_password"),
path("account_settings/", AccountSettingsView.as_view(), name="account_settings"),
]
urlpatterns = [

View file

@ -1,13 +1,18 @@
from django.views.generic import TemplateView, RedirectView
from django.views.generic.edit import UpdateView
from django.shortcuts import redirect
from django.urls import reverse
from django.dispatch import receiver
from django.contrib.auth import logout as auth_logout
from django.contrib.auth import user_logged_in, user_logged_out, user_login_failed
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import PasswordChangeView
from django.contrib import messages
from urllib.parse import quote as urlquote
from .forms import AccountSettingsForm
class LoginView(TemplateView):
template_name = "registration/login_switch.html"
@ -81,3 +86,26 @@ def on_logout(request, **kwargs):
@receiver(user_login_failed)
def on_login_failed(request, **kwargs):
messages.error(request, "Connexion échouée.")
class PasswordChangeView(PasswordChangeView):
template_name = "registration/change_password.html"
def get_success_url(self):
messages.info(self.request, "Mot de passe mis à jour")
return reverse("gestiojeux_auth:account_settings")
class AccountSettingsView(LoginRequiredMixin, UpdateView):
template_name = "registration/account_settings.html"
form_class = AccountSettingsForm
def get_object(self):
return self.request.user
def get_success_url(self):
return self.request.get_full_path()
def form_valid(self, form):
messages.success(self.request, "Paramètres du compte mis à jour")
return super().form_valid(form)

View file

@ -4,11 +4,9 @@
<h1><i class="fa fa-bookmark" aria-hidden="true"></i> {{ category.name }}</h1>
{% with game_list=category.game_set.all %}
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} dans cette catégorie&nbsp;:
<ul>
{% for game in game_list %}
<li>{% include "./partials/game_item.html" %}</li>
{% endfor %}
</ul>
<p>Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} dans cette catégorie&nbsp;:</p>
{% for game in game_list %}
{% include "./partials/game_item.html" %}
{% endfor %}
{% endwith %}
{% endblock %}

View file

@ -3,10 +3,8 @@
{% block "content" %}
<h1>Liste des catégories</h1>
Il y a {{ category_list|length }} catégorie{{ category_list|pluralize }} de jeux&nbsp;:
<ul>
{% for category in category_list %}
<li>{% include "./partials/category_item.html" %}</li>
{% endfor %}
</ul>
<p>Il y a {{ category_list|length }} catégorie{{ category_list|pluralize }} de jeux&nbsp;:</p>
{% for category in category_list %}
{% include "./partials/category_item.html" %}
{% endfor %}
{% endblock %}

View file

@ -38,32 +38,34 @@
{% endif %}
<h2>Commentaires et propositions de variantes</h2>
<ul>
{% for comment in game.comments.all %}
{% if comment == edited_comment %}
<li id="edited_comment">
<form class="comment" method="post">
{% csrf_token %}
<textarea name="comment_text" required>{{ comment.text }}</textarea>
<button type="submit"><i class="fa fa-pencil" aria-hidden="true"></i> Modifier mon commentaire</button>
</form>
</li>
{% else %}
<li class="comment">
<form id="edited_comment" class="comment" method="post">
<div class="meta">
<span class="author">{{ comment.author }}</span>
<span class="author">{% include "partials/user.html" with user=comment.author %}</span>
<span class="date">posté le {{ comment.created_on|date }} à {{ comment.created_on|time }}</span>
<a href="{% url "inventory:game" game.slug %}" title="Annuler la modification"><i class="fa fa-ban" aria-hidden="true"></i></a>
</div>
{% csrf_token %}
<textarea name="comment_text" required>{{ comment.text }}</textarea>
<button type="submit"><i class="fa fa-pencil" aria-hidden="true"></i> Modifier mon commentaire</button>
</form>
{% else %}
<div class="comment">
<div class="meta">
<span class="author">{% include "partials/user.html" with user=comment.author %}</span>
<span class="date">posté le {{ comment.created_on|date }} à {{ comment.created_on|time }}{% if comment.created_on|date:"YmdHi" != comment.modified_on|date:"YmdHi" %}, dernière modification le {{ comment.modified_on|date }} à {{ comment.modified_on|time }}{% endif %}</span>
{% if comment.author == request.user %}
<a href="{% url "inventory:modify_game_comment" game.slug comment.id %}#edited_comment"><i class="fa fa-pencil" aria-hidden="true"></i></a>
<a href="{% url "inventory:modify_game_comment" game.slug comment.id %}#edited_comment" title="Éditer mon commentaire"><i class="fa fa-pencil" aria-hidden="true"></i></a>
{% endif %}
</div>
{{ comment.text|linebreaks }}
</li>
</div>
{% endif %}
{% empty %}
<li>(Aucun commentaire sur ce jeu)</li>
(Aucun commentaire sur ce jeu)
{% endfor %}
</ul>
{% if not edited_comment %}
{% if request.user.is_authenticated %}
<form class="comment" method="post" action="{% url "inventory:add_game_comment" game.slug %}">

View file

@ -3,10 +3,8 @@
{% block "content" %}
<h1>Liste des jeux</h1>
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} en salle jeux&nbsp;:
<ul>
{% for game in game_list %}
<li>{% include "./partials/game_item.html" %}</li>
{% endfor %}
</ul>
<p>Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} en salle jeux&nbsp;:</p>
{% for game in game_list %}
{% include "./partials/game_item.html" %}
{% endfor %}
{% endblock %}

View file

@ -12,7 +12,6 @@
<hr/>
<div class="btn_row">
<a href="{% url "inventory:category_list" %}">
Liste des catégories
<p class="helptext">

View file

@ -10,9 +10,7 @@
{% if query %}
<hr/>
<ul>
{% for result in page_obj.object_list %}
<li>
{% if result.model_name == "game" %}
{% include "./partials/game_item.html" with game=result.object %}
{% elif result.model_name == "category" %}
@ -20,11 +18,9 @@
{% elif result.model_name == "tag" %}
{% include "./partials/tag_item.html" with tag=result.object %}
{% endif %}
</li>
{% empty %}
<li>Aucun résultat trouvé</li>
Aucun résultat trouvé
{% endfor %}
</ul>
{% include "./partials/pagination.html" %}
{% endif %}

View file

@ -4,11 +4,9 @@
<h1><i class="fa fa-tag" aria-hidden="true"></i> {{ tag.name }}</h1>
{% with game_list=tag.game_set.all %}
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} marqué{{ game_list|pluralize }} avec ce tag&nbsp;:
<ul>
{% for game in game_list %}
<li>{% include "./partials/game_item.html" %}</li>
{% endfor %}
</ul>
<p>Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} marqué{{ game_list|pluralize }} avec ce tag&nbsp;:</p>
{% for game in game_list %}
{% include "./partials/game_item.html" %}
{% endfor %}
{% endwith %}
{% endblock %}

View file

@ -3,10 +3,8 @@
{% block "content" %}
<h1>Liste des tags</h1>
Il y a {{ tag_list|length }} tag{{ tag_list|pluralize }} dans la ludothèque&nbsp;:
<ul>
{% for tag in tag_list %}
<li>{% include "./partials/tag_item.html" %}</li>
{% endfor %}
</ul>
<p>Il y a {{ tag_list|length }} tag{{ tag_list|pluralize }} dans la ludothèque&nbsp;:</p>
{% for tag in tag_list %}
{% include "./partials/tag_item.html" %}
{% endfor %}
{% endblock %}

View file

@ -22,6 +22,7 @@ form {
}
.helptext {
display: block;
font-size: 0.7em;
color: $help_text_color;
}
@ -120,7 +121,9 @@ form.search {
}
form.comment {
font-size: 0.7em;
padding: 0;
border: none;
textarea {
border-radius: 10px 10px 0 0;
border-bottom: none;
@ -130,4 +133,19 @@ form.comment {
border-radius: 0 0 10px 10px;
margin: 0;
}
}
form#edited_comment {
.meta {
padding: 10px;
padding-bottom: 5px;
border-radius: 10px 10px 0 0;
border: 1px solid $indexbar_bg_color_1;
border-bottom: none;
}
textarea {
border-radius: 0;
}
}

View file

@ -55,15 +55,6 @@ footer {
padding: 10px;
}
.help_bubble {
@media (min-width: 700px) {
font-size: 0.7em;
position: relative;
bottom: 0.3ex;
left: 0.2ex;
}
}
h1 {
font-size: 1.5em;
font-weight: bold;
@ -107,6 +98,11 @@ hr {
margin: 30px 60px;
}
ul, ol {
padding: 0;
list-style-position: inside;
}
.btn_row {
display: flex;
align-items: stretch;
@ -139,49 +135,6 @@ button, .btn_row a {
.warning { @include warning_box; }
.success { @include success_box; }
.tooltip {
position: relative;
display: inline-block;
opacity: 0.75;
border-radius: 3px;
.tooltiptext {
visibility: hidden;
display: block;
background-color: black;
color: rgba(white, 0.80);
text-align: justify;
padding: 10px;
border-radius: 6px;
font-size: 0.8em;
width: 250px;
@media (max-width: 400px) {
width: 150px;
position: absolute;
left: -75px;
}
/* Position the tooltip text - see examples below! */
position: absolute;
left: -75px;
z-index: 1;
ul {
margin: 0;
padding-left: 15px;
color: inherit;
}
}
&:hover, &:focus {
opacity: 1;
.tooltiptext {
visibility: visible;
}
}
}
.antispam {
unicode-bidi: bidi-override;
direction: rtl;
@ -286,11 +239,6 @@ iframe {
}
}
ul {
padding: 0;
list-style-type: none;
}
a.inventory_item {
display: block;
padding: 15px;
@ -326,7 +274,7 @@ a.inventory_item {
}
}
li.comment {
.comment {
@include box(white, $indexbar_bg_color_1);
margin: 1em 0;
font-size: 0.7em;

View file

@ -57,6 +57,7 @@ form {
width: 100%; }
.helptext {
display: block;
font-size: 0.7em;
color: rgba(37, 15, 45, 0.65); }
@ -173,7 +174,8 @@ form.search {
border-radius: 0 10px 10px 0; }
form.comment {
font-size: 0.7em; }
padding: 0;
border: none; }
form.comment textarea {
border-radius: 10px 10px 0 0;
border-bottom: none;
@ -182,6 +184,16 @@ form.comment {
border-radius: 0 0 10px 10px;
margin: 0; }
form#edited_comment .meta {
padding: 10px;
padding-bottom: 5px;
border-radius: 10px 10px 0 0;
border: 1px solid rgba(107, 184, 196, 0.75);
border-bottom: none; }
form#edited_comment textarea {
border-radius: 0; }
html {
box-sizing: border-box; }
@ -221,13 +233,6 @@ footer {
text-align: center;
padding: 10px; }
@media (min-width: 700px) {
.help_bubble {
font-size: 0.7em;
position: relative;
bottom: 0.3ex;
left: 0.2ex; } }
h1 {
font-size: 1.5em;
font-weight: bold; }
@ -262,6 +267,10 @@ hr {
border: 1px solid #c9dbe0;
margin: 30px 60px; }
ul, ol {
padding: 0;
list-style-position: inside; }
.btn_row {
display: flex;
align-items: stretch;
@ -319,39 +328,6 @@ button, .btn_row a {
border: 1px solid #84ff72;
background-color: #ddffd8; }
.tooltip {
position: relative;
display: inline-block;
opacity: 0.75;
border-radius: 3px; }
.tooltip .tooltiptext {
visibility: hidden;
display: block;
background-color: black;
color: rgba(255, 255, 255, 0.8);
text-align: justify;
padding: 10px;
border-radius: 6px;
font-size: 0.8em;
width: 250px;
/* Position the tooltip text - see examples below! */
position: absolute;
left: -75px;
z-index: 1; }
@media (max-width: 400px) {
.tooltip .tooltiptext {
width: 150px;
position: absolute;
left: -75px; } }
.tooltip .tooltiptext ul {
margin: 0;
padding-left: 15px;
color: inherit; }
.tooltip:hover, .tooltip:focus {
opacity: 1; }
.tooltip:hover .tooltiptext, .tooltip:focus .tooltiptext {
visibility: visible; }
.antispam {
unicode-bidi: bidi-override;
direction: rtl; }
@ -436,10 +412,6 @@ iframe {
#game_infos #details hr {
margin: 1ex; }
ul {
padding: 0;
list-style-type: none; }
a.inventory_item {
display: block;
padding: 15px;
@ -465,16 +437,16 @@ a.inventory_item {
background-color: white;
box-shadow: 0 0 1.5px 1px #6bb8c4; }
li.comment {
.comment {
border-radius: 10px;
padding: 10px;
border: 1px solid rgba(107, 184, 196, 0.75);
background-color: white;
margin: 1em 0;
font-size: 0.7em; }
li.comment .author {
.comment .author {
font-weight: bold; }
li.comment .date {
.comment .date {
font-size: 0.7em; }
li.comment p {
.comment p {
margin: 0.5em; }

View file

@ -11,7 +11,7 @@
{% endif %}
</nav>
{% if request.user.is_authenticated %}
<div class="username">{{ request.user.username }}</div>
<a class="username" href="{% url "gestiojeux_auth:account_settings" %}">{% include "./user.html" with user=request.user %}</a>
<a class="login" href="{% url "gestiojeux_auth:logout" %}?next={{ request.get_full_path }}"><i class="fa fa-sign-out" aria-hidden="true"></i></a>
{% else %}
<a class="login{% if url_name == "login" %} current{% endif %}" href="{% url "gestiojeux_auth:login" %}?next={{ request.get_full_path }}">Connexion</a>

View file

@ -0,0 +1 @@
{% if user.first_name %}{{ user.first_name }}{% else %}{{ user.username }}{% endif %}