Merge branch 'dev' into preprod
This commit is contained in:
commit
dbf44746d9
|
@ -2,6 +2,7 @@
|
|||
__pycache__/
|
||||
app/__pycache__/
|
||||
app/static/avatars/
|
||||
app/static/images/trophies/
|
||||
|
||||
## Devlopement files
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ from flask_login import LoginManager
|
|||
from flask_mail import Mail
|
||||
from config import Config
|
||||
import time
|
||||
import slugify
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object(Config)
|
||||
|
@ -49,3 +50,8 @@ from app.routes.forum import index, topic
|
|||
from app.utils import pluralize # To use pluralize into the templates
|
||||
from app.utils import date
|
||||
from app.utils import is_title
|
||||
|
||||
# Add slugify into the available functions in every template
|
||||
app.jinja_env.globals.update(
|
||||
slugify=slugify.slugify
|
||||
)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
|
@ -2,6 +2,7 @@
|
|||
# name Trophy name as displayed on the site.
|
||||
# is_title If True, the trophy can be worn as a title next to the avatar.
|
||||
# description Detailed description to be shown on profile page.
|
||||
# hidden Not shown unless awarded (for unique titles).
|
||||
|
||||
# Manually awarded
|
||||
-
|
||||
|
@ -185,3 +186,8 @@
|
|||
is_title: True
|
||||
description: Foudroyer les cœurs à 5 reprises !
|
||||
hidden: False
|
||||
-
|
||||
name: Survivant de la v42
|
||||
is_title: False
|
||||
description: A connu la v42 de Planète Casio.
|
||||
hidden: True
|
||||
|
|
|
@ -189,8 +189,8 @@ class AdminUpdateAccountForm(FlaskForm):
|
|||
vd.email,
|
||||
],
|
||||
)
|
||||
email_validate = BooleanField(
|
||||
"Envoyer un email de validation à la nouvelle adresse",
|
||||
email_confirmed = BooleanField(
|
||||
"Confirmer l'email",
|
||||
description="Si décoché, l'utilisateur devra demander explicitement un email "\
|
||||
"de validation, ou faire valider son adresse email par un administrateur.",
|
||||
)
|
||||
|
|
|
@ -160,14 +160,15 @@ class Member(User):
|
|||
"""
|
||||
Update all or part of the user's metadata. The [data] dictionary
|
||||
accepts the following keys:
|
||||
"email" str User mail ddress
|
||||
"password" str Raw password
|
||||
"bio" str Biograpy
|
||||
"signature" str Post signature
|
||||
"birthday" date Birthday date
|
||||
"newsletter" bool Newsletter setting
|
||||
"xp" int Experience points
|
||||
"avatar" File Avatar image
|
||||
"email" str User mail address
|
||||
"email_confirmed" bool User mail address confirmed
|
||||
"password" str Raw password
|
||||
"bio" str Biograpy
|
||||
"signature" str Post signature
|
||||
"birthday" date Birthday date
|
||||
"newsletter" bool Newsletter setting
|
||||
"xp" int Experience points
|
||||
"avatar" File Avatar image
|
||||
For future compatibility, other attributes are silently ignored. None
|
||||
values can be specified and are ignored.
|
||||
|
||||
|
@ -198,6 +199,8 @@ class Member(User):
|
|||
self.set_avatar(data["avatar"])
|
||||
|
||||
# For admins only
|
||||
if "email_confirmed" in data:
|
||||
self.email_confirmed = data["email_confirmed"]
|
||||
if "xp" in data:
|
||||
self.xp = data["xp"]
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ def adm_edit_account(user_id):
|
|||
avatar=form.avatar.data or None,
|
||||
name=form.username.data or None,
|
||||
email=form.email.data or None,
|
||||
email_confirmed=form.email_confirmed.data,
|
||||
password=form.password.data or None,
|
||||
birthday=form.birthday.data,
|
||||
signature=form.signature.data,
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
table {
|
||||
border-collapse: collapse;
|
||||
border-color: #d8d8d8;
|
||||
border-collapse: collapse;
|
||||
border-color: var(--border);
|
||||
border-style: solid;
|
||||
border-width: 0 0 1px 0;
|
||||
}
|
||||
table tr:nth-child(even) {
|
||||
background: rgba(0, 0, 0, .05);
|
||||
background: var(--background);
|
||||
}
|
||||
table tr:nth-child(even) {
|
||||
background: var(--background);
|
||||
}
|
||||
table th {
|
||||
background: #e0e0e0;
|
||||
border-color: #d0d0d0;
|
||||
background: var(--background);
|
||||
border-color: var(--border);
|
||||
border-style: solid;
|
||||
border-width: 1px 0;
|
||||
padding: 2px 6px;
|
||||
|
|
|
@ -25,6 +25,17 @@
|
|||
--hr-border: 1px solid #b0b0b0;
|
||||
}
|
||||
|
||||
table {
|
||||
--border: #d8d8d8;
|
||||
}
|
||||
table tr:nth-child(even) {
|
||||
--background: rgba(0, 0, 0, .05);
|
||||
}
|
||||
table th {
|
||||
--background: #e0e0e0;
|
||||
--border: #d0d0d0;
|
||||
}
|
||||
|
||||
.form {
|
||||
--background: #ffffff;
|
||||
--text: #000000;
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
border-radius: 2px;
|
||||
}
|
||||
.trophy img {
|
||||
height: 50px; margin-right: 5px;
|
||||
height: 48px; margin-right: 8px;
|
||||
}
|
||||
.trophy div > * {
|
||||
display: block;
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
<div class="trophies">
|
||||
{% for t in trophies if t in member.trophies or t.hidden == False %}
|
||||
<div class="trophy {{ '' if t in member.trophies else 'disabled' }}">
|
||||
<img src="{{ url_for('static', filename='images/fa_124.png') }}">
|
||||
<img src="{{ url_for('static', filename='images/trophies/'+slugify(t.name))+'.png' }}">
|
||||
<div>
|
||||
<em>{{ t.name }}</em>
|
||||
<span>{{ t.description }}</span>
|
||||
|
|
|
@ -37,9 +37,9 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
<div>
|
||||
{{ form.email_validate.label }}
|
||||
{{ form.email_validate(checked=True) }}
|
||||
<div class=desc>{{ form.email_validate.description }}</div>
|
||||
{{ form.email_confirmed.label }}
|
||||
{{ form.email_confirmed(checked=user.email_confirmed) }}
|
||||
<div class=desc>{{ form.email_confirmed.description }}</div>
|
||||
</div>
|
||||
<div>
|
||||
{{ form.password.label }}
|
||||
|
|
|
@ -13,19 +13,19 @@
|
|||
|
||||
<table style="width:90%; margin: auto;">
|
||||
<tr><th>Pseudo</th><th>Email</th><th>Groupes</th>
|
||||
<th>Privilèges spéciaux</th><th>Modifier</th></tr>
|
||||
<th>Privilèges spéciaux</th><th>Modifier</th></tr>
|
||||
|
||||
{% for user in users %}
|
||||
<tr><td><a href="{{ url_for('user_by_id', user_id=user.id) }}" title="Page de profil publique de {{ user.name }}">{{ user.name }}</a></td>
|
||||
<td>{{ user.email }}</td>
|
||||
<td style="color: {{ 'red' if not user.email_confirmed else 'inherit' }};">{{ user.email }}</td>
|
||||
<td>{% for g in user.groups %}
|
||||
<span style="{{ g.css }}">{{ g.name }}</span>
|
||||
{{ ', ' if not loop.last }}
|
||||
{% endfor %}</td>
|
||||
<span style="{{ g.css }}">{{ g.name }}</span>
|
||||
{{ ', ' if not loop.last }}
|
||||
{% endfor %}</td>
|
||||
<td>{% for priv in user.special_privileges() %}
|
||||
<code>{{ priv }}</code>
|
||||
{{- ', ' if not loop.last }}
|
||||
{% endfor %}</td>
|
||||
<code>{{ priv }}</code>
|
||||
{{- ', ' if not loop.last }}
|
||||
{% endfor %}</td>
|
||||
<td style="text-align: center"><a href="{{ url_for('adm_edit_account', user_id=user.id) }}">Modifier</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
27
master.py
27
master.py
|
@ -10,6 +10,8 @@ import os
|
|||
import sys
|
||||
import yaml
|
||||
import readline
|
||||
import slugify
|
||||
from PIL import Image
|
||||
|
||||
help_msg = """
|
||||
This is the Planète Casio master shell. Type 'exit' or C-D to leave.
|
||||
|
@ -37,7 +39,7 @@ the database.
|
|||
|
||||
Type 'add-group <member> #<group-id>' to add a new member to a group.
|
||||
|
||||
Type 'create-trophies' to reset trophies and titles.
|
||||
Type 'create-trophies' to reset trophies and titles and their icons.
|
||||
|
||||
Type 'create-forums' to reset the forum tree.
|
||||
"""
|
||||
|
@ -183,6 +185,29 @@ def create_trophies():
|
|||
|
||||
print(f"Created {len(tr)} trophies.")
|
||||
|
||||
# Create their icons in /app/static/images/trophies
|
||||
names = [ slugify.slugify(t["name"]) for t in tr ]
|
||||
src = os.path.join(app.root_path, "data", "trophies.png")
|
||||
dst = os.path.join(app.root_path, "static", "images", "trophies")
|
||||
|
||||
try:
|
||||
os.mkdir(dst)
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
img = Image.open(src)
|
||||
|
||||
def trophy_iterator(img):
|
||||
for y in range(img.height // 26):
|
||||
for x in range(img.width // 26):
|
||||
icon = img.crop((26*x+1, 26*y+1, 26*x+25, 26*y+25))
|
||||
# Skip blank squares in the source image
|
||||
if len(icon.getcolors()) > 1:
|
||||
yield icon.resize((48,48))
|
||||
|
||||
for (name, icon) in zip(names, trophy_iterator(img)):
|
||||
icon.save(os.path.join(dst, f"{name}.png"))
|
||||
|
||||
def create_forums():
|
||||
# Clean up forums
|
||||
forums("clear")
|
||||
|
|
Loading…
Reference in New Issue