forked from devs/PCv5
trophies: automatically remove undeserved trophies
... and other minor edits from the trophies branch.
This commit is contained in:
parent
4d91ed65da
commit
4cefe39c36
|
@ -1,3 +1,8 @@
|
|||
# This is a list of trophies. For each trophies, the following keys may be set:
|
||||
# name Trophy name as displayed on the site.
|
||||
# is_title If True, the trophy can be worn as a title next to the avatar.
|
||||
|
||||
# Manually awarded
|
||||
-
|
||||
name: Membre de CreativeCalc
|
||||
is_title: True
|
||||
|
@ -11,28 +16,37 @@
|
|||
name: Gourou
|
||||
is_title: True
|
||||
-
|
||||
name: Grand Maitre des traits d'esprit
|
||||
name: Grand Maître des traits d'esprit
|
||||
is_title: True
|
||||
|
||||
# Number of posts of any kind
|
||||
-
|
||||
name: Premiers mots
|
||||
is_title: False
|
||||
-
|
||||
name: Beau parleur
|
||||
is_title: False
|
||||
-
|
||||
name: Jeune écrivain
|
||||
name: Plume infaillible
|
||||
is_title: False
|
||||
-
|
||||
name: Romancier émérite
|
||||
is_title: True
|
||||
|
||||
# Number of posted tutorials
|
||||
-
|
||||
name: Apprenti instructeur
|
||||
is_title: False
|
||||
-
|
||||
name: Pédagogue averti
|
||||
name: Pédagogue
|
||||
is_title: False
|
||||
-
|
||||
name: Encyclopédie vivante
|
||||
is_title: True
|
||||
is_title: False
|
||||
-
|
||||
name: Nouveau
|
||||
name: Guerrier du savoir
|
||||
is_title: True
|
||||
|
||||
# Account age (awarded on login only)
|
||||
-
|
||||
name: Initié
|
||||
is_title: False
|
||||
-
|
||||
name: Aficionado
|
||||
|
@ -43,6 +57,11 @@
|
|||
-
|
||||
name: Papy Casio
|
||||
is_title: True
|
||||
-
|
||||
name: Vétéran mythique
|
||||
is_title: True
|
||||
|
||||
# Number of "good" programs
|
||||
-
|
||||
name: Programmeur du dimanche
|
||||
is_title: False
|
||||
|
@ -52,33 +71,41 @@
|
|||
-
|
||||
name: Je code donc je suis
|
||||
is_title: True
|
||||
|
||||
# Number of posted tests
|
||||
-
|
||||
name: Testeur
|
||||
is_title: False
|
||||
-
|
||||
name: Examinateur
|
||||
name: Grand joueur
|
||||
is_title: False
|
||||
-
|
||||
name: Hard tester
|
||||
is_title: True
|
||||
|
||||
# Number of event participations
|
||||
-
|
||||
name: Participant avéré
|
||||
name: Participant
|
||||
is_title: False
|
||||
-
|
||||
name: Concourant encore
|
||||
is_title: False
|
||||
-
|
||||
name: Concurrent de l’extrême
|
||||
name: Concurrent de l'extrême
|
||||
is_title: True
|
||||
|
||||
# Number of posted art
|
||||
-
|
||||
name: Designer en herbe
|
||||
name: Dessinateur en herbe
|
||||
is_title: False
|
||||
-
|
||||
name: Graphiste expérimenté
|
||||
name: Open pixel
|
||||
is_title: False
|
||||
-
|
||||
name: Roi du pixel
|
||||
is_title: True
|
||||
|
||||
# Miscellaneous automatically awarded
|
||||
-
|
||||
name: Actif
|
||||
is_title: False
|
||||
|
|
|
@ -51,7 +51,7 @@ class AdminUpdateAccountForm(FlaskForm):
|
|||
|
||||
|
||||
class AdminAccountEditTrophyForm(FlaskForm):
|
||||
# Boolean inputs are generated on-the-fly from trophies list
|
||||
# Boolean inputs are generated on-the-fly from trophy list
|
||||
submit = SubmitField('Modifier')
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from flask_wtf.file import FileField # Cuz' wtforms' FileField is shitty
|
|||
|
||||
class TrophyForm(FlaskForm):
|
||||
name = StringField('Nom', validators=[DataRequired()])
|
||||
icon = FileField('Icone')
|
||||
icon = FileField('Icône')
|
||||
title = BooleanField('Titre', description='Un titre peut être affiché en dessous du pseudo.', validators=[Optional()])
|
||||
css = StringField('CSS', description='CSS appliqué au titre, le cas échéant.')
|
||||
submit = SubmitField('Envoyer')
|
||||
|
|
|
@ -4,15 +4,16 @@ from app import db
|
|||
class Trophy(db.Model):
|
||||
__tablename__ = 'trophy'
|
||||
|
||||
# Trophy ID and type (polymorphic discriminator)
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
# Trophy type (polymorphic discriminator)
|
||||
type = db.Column(db.String(20))
|
||||
|
||||
__mapper_args__ = {
|
||||
'polymorphic_identity': __tablename__,
|
||||
'polymorphic_on': type
|
||||
}
|
||||
# Standalone properties
|
||||
|
||||
# Trophy name (in French)
|
||||
name = db.Column(db.Unicode(64), index=True)
|
||||
|
||||
owners = db.relationship('Member', secondary=lambda: TrophyMember,
|
||||
|
@ -21,6 +22,9 @@ class Trophy(db.Model):
|
|||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Trophy: {self.name}>'
|
||||
|
||||
# Title: Rare trophies that can be displayed along one's name
|
||||
class Title(Trophy):
|
||||
__tablename__ = 'title'
|
||||
|
@ -29,10 +33,13 @@ class Title(Trophy):
|
|||
id = db.Column(db.Integer, db.ForeignKey('trophy.id'), primary_key=True)
|
||||
css = db.Column(db.UnicodeText)
|
||||
|
||||
def __init__(self, name, css):
|
||||
def __init__(self, name, css=""):
|
||||
self.name = name
|
||||
self.css = css
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Title: {self.name}>'
|
||||
|
||||
|
||||
# Many-to-many relation for users earning trophies
|
||||
TrophyMember = db.Table('trophy_member', db.Model.metadata,
|
||||
|
|
|
@ -33,7 +33,7 @@ class User(UserMixin, db.Model):
|
|||
}
|
||||
|
||||
def __repr__(self):
|
||||
return f'<User #{self.id}>'
|
||||
return f'<User: #{self.id}>'
|
||||
|
||||
# Guest: Unregistered user with minimal privileges
|
||||
class Guest(User, db.Model):
|
||||
|
@ -215,8 +215,6 @@ class Member(User, db.Model):
|
|||
t = Trophy.query.filter_by(name=t).first()
|
||||
if t not in self.trophies:
|
||||
self.trophies.append(t)
|
||||
db.session.merge(self)
|
||||
db.session.commit()
|
||||
# TODO: implement the notification system
|
||||
# self.notify(f"Vous venez de débloquer le trophée '{t.name}'")
|
||||
|
||||
|
@ -231,8 +229,6 @@ class Member(User, db.Model):
|
|||
t = Trophy.query.filter_by(name=name).first()
|
||||
if t in self.trophies:
|
||||
self.trophies.remove(t)
|
||||
db.session.merge(self)
|
||||
db.session.commit()
|
||||
|
||||
def update_trophies(self, context=None):
|
||||
"""
|
||||
|
@ -243,43 +239,131 @@ class Member(User, db.Model):
|
|||
- new-tutorial
|
||||
- new-test
|
||||
- new-event-participation
|
||||
- new-picture
|
||||
- on-program-reward
|
||||
- new-art
|
||||
- on-program-tested
|
||||
- on-program-rewarded
|
||||
- on-login
|
||||
- on-profile-update
|
||||
"""
|
||||
|
||||
if context == "new-post" or context is None:
|
||||
pass
|
||||
if context == "new-program" or context is None:
|
||||
pass
|
||||
if context == "new-tutorial" or context is None:
|
||||
pass
|
||||
if context == "new-test" or context is None:
|
||||
pass
|
||||
if context == "new-event-participation" or context is None:
|
||||
pass
|
||||
if context == "new-picture" or context is None:
|
||||
pass
|
||||
if context == "on-program-reward" or context is None:
|
||||
pass
|
||||
if context == "on-login" or context is None:
|
||||
def progress(trophies, value):
|
||||
"""Award or delete all trophies from a progressive category."""
|
||||
for level in trophies:
|
||||
if value >= level:
|
||||
self.add_trophy(trophies[level])
|
||||
else:
|
||||
self.del_trophy(trophies[level])
|
||||
|
||||
if context in ["new-post", "new-program", "new-tutorial", "new-test",
|
||||
None]:
|
||||
# TODO: Amount of posts by the user
|
||||
post_count = 0
|
||||
|
||||
levels = {
|
||||
20: "Premiers mots",
|
||||
500: "Beau parleur",
|
||||
1500: "Plume infaillible",
|
||||
5000: "Romancier émérite",
|
||||
}
|
||||
progress(levels, post_count)
|
||||
|
||||
if context in ["new-program", None]:
|
||||
# TODO: Amount of programs by the user
|
||||
program_count = 0
|
||||
|
||||
levels = {
|
||||
5: "Programmeur du dimanche",
|
||||
10: "Codeur invétéré",
|
||||
20: "Je code donc je suis",
|
||||
}
|
||||
progress(levels, program_count)
|
||||
|
||||
if context in ["new-tutorial", None]:
|
||||
# TODO: Number of tutorials by user
|
||||
tutorial_count = 0
|
||||
|
||||
levels = {
|
||||
5: "Pédagogue",
|
||||
10: "Encyclopédie vivante",
|
||||
25: "Guerrier du savoir",
|
||||
}
|
||||
progress(levels, tutorial_count)
|
||||
|
||||
if context in ["new-test", None]:
|
||||
# TODO: Number of tests by user
|
||||
test_count = 0
|
||||
|
||||
levels = {
|
||||
5: "Testeur",
|
||||
25: "Grand joueur",
|
||||
100: "Hard tester",
|
||||
}
|
||||
progress(levels, test_count)
|
||||
|
||||
if context in ["new-event-participation", None]:
|
||||
# TODO: Number of event participations by user
|
||||
event_participations = 0
|
||||
|
||||
levels = {
|
||||
1: "Participant",
|
||||
5: "Concourant encore",
|
||||
15: "Concurrent de l'extrême",
|
||||
}
|
||||
progress(levels, event_participations)
|
||||
|
||||
if context in ["new-art", None]:
|
||||
# TODO: Number of art posts by user
|
||||
art_count = 0
|
||||
|
||||
levels = {
|
||||
5: "Dessinateur en herbe",
|
||||
30: "Open pixel",
|
||||
100: "Roi du pixel",
|
||||
}
|
||||
progress(levels, art_count)
|
||||
|
||||
if context in ["on-program-tested", None]:
|
||||
# TODO: Number of "coups de coeur" of user
|
||||
heart_count = 0
|
||||
|
||||
levels = {
|
||||
5: "Bourreau des cœurs",
|
||||
}
|
||||
progress(levels, heart_count)
|
||||
|
||||
if context in ["on-program-rewarded", None]:
|
||||
# TODO: Number of programs with labels
|
||||
label_count = 0
|
||||
|
||||
levels = {
|
||||
5: "Maître du code",
|
||||
}
|
||||
progress(levels, label_count)
|
||||
|
||||
if context in ["on-login", None]:
|
||||
# Seniority-based trophies
|
||||
age = date.today() - self.register_date
|
||||
if age.days > 30:
|
||||
self.add_trophy("Nouveau")
|
||||
if age.days > 365.25:
|
||||
self.add_trophy("Aficionado")
|
||||
if age.days > 365.25 * 2:
|
||||
self.add_trophy("Veni, vidi, casii")
|
||||
if age.days > 365.25 * 5:
|
||||
self.add_trophy("Papy Casio")
|
||||
if context == "on-profile-update" or context is None:
|
||||
|
||||
levels = {
|
||||
30: "Initié",
|
||||
365.25: "Aficionado",
|
||||
365.25 * 2: "Veni, vidi, casii",
|
||||
365.25 * 5: "Papy Casio",
|
||||
365.25 * 10: "Vétéran mythique",
|
||||
}
|
||||
progress(levels, age.days)
|
||||
|
||||
# TODO: Trophy "actif"
|
||||
|
||||
if context in ["on-profile-update", None]:
|
||||
# TODO: add a better condition (this is for test)
|
||||
self.add_trophy("Artiste")
|
||||
|
||||
db.session.merge(self)
|
||||
db.session.commit()
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Member: {self.name}>'
|
||||
return f'<Member: {self.name} ({self.norm})>'
|
||||
|
||||
|
||||
@app.login.user_loader
|
||||
|
|
|
@ -62,20 +62,18 @@ def adm_edit_account(user_id):
|
|||
else:
|
||||
print(f"Del trophy {id[1:]}")
|
||||
user.del_trophy(int(id[1:]))
|
||||
|
||||
db.session.merge(user)
|
||||
db.session.commit()
|
||||
else:
|
||||
flash("Erreur lors de l'ajout du trophée", 'error')
|
||||
|
||||
# if deltrophy_form.submit.data:
|
||||
# if deltrophy_form.validate_on_submit():
|
||||
# trophy = Trophy.query.get(deltrophy_form.trophy.data)
|
||||
# if trophy is not None:
|
||||
# user.del_trophy(trophy)
|
||||
# flash('Trophée retiré', 'ok')
|
||||
# else:
|
||||
# flash("Erreur lors du retrait du trophée", 'error')
|
||||
user_owned = set()
|
||||
for t in user.trophies:
|
||||
user_owned.add(f"t{t.id}")
|
||||
|
||||
return render('admin/edit_account.html', user=user,
|
||||
form=form, trophy_form=trophy_form)
|
||||
form=form, trophy_form=trophy_form, user_owned=user_owned)
|
||||
|
||||
|
||||
@app.route('/admin/account/<user_id>/delete', methods=['GET', 'POST'])
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form form label {
|
||||
.form form label,
|
||||
.trophies-panel p {
|
||||
display: inline-block;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
@ -19,16 +20,13 @@
|
|||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.form input {
|
||||
cursor: pointer; /* don't know why it is not a cursor by default */
|
||||
}
|
||||
|
||||
.form input[type='text'],
|
||||
.form input[type='email'],
|
||||
.form input[type='date'],
|
||||
.form input[type='password'],
|
||||
.form input[type='search'],
|
||||
.form textarea {
|
||||
.form textarea,
|
||||
.trophies-panel > div {
|
||||
display: block;
|
||||
width: 100%; padding: 6px 8px;
|
||||
border: 1px solid #c8c8c8;
|
||||
|
@ -51,6 +49,12 @@
|
|||
resize: vertical;
|
||||
}
|
||||
|
||||
.form input[type="checkbox"],
|
||||
.form input[type="radio"] {
|
||||
display: inline;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.form input[type="submit"] {
|
||||
/*width: 20%;*/
|
||||
}
|
||||
|
@ -66,14 +70,19 @@
|
|||
color: gray;
|
||||
}
|
||||
|
||||
.trophies-panel {
|
||||
display: flex; flex-wrap: wrap;
|
||||
}
|
||||
.trophies-panel > div {
|
||||
margin: 3px 5px; padding: 3px;
|
||||
border: 1px solid #969696;
|
||||
border-radius: 3px;
|
||||
.form hr {
|
||||
color: white;
|
||||
height: 3px;
|
||||
border: 0 solid #b0b0b0;
|
||||
border-width: 1px 0;
|
||||
margin: 24px 0;
|
||||
}
|
||||
.trophies-panel label {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.trophies-panel p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.trophies-panel p label {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
|
@ -40,29 +40,6 @@ section ul {
|
|||
line-height: 24px;
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
|
||||
input,
|
||||
textarea {
|
||||
display: block;
|
||||
background: #FFFFFF; color: #000000;
|
||||
border: none;
|
||||
}
|
||||
input:focus:not(type="button"),
|
||||
textarea:focus {
|
||||
box-shadow: 0 0 0 0.2rem rgba(0,123,255,0.25);
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
border: 1px solid #eeeeee;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
display: inline;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
.button,
|
||||
|
@ -71,6 +48,7 @@ input[type="submit"] {
|
|||
padding: 6px 10px; border-radius: 2px;
|
||||
cursor: pointer;
|
||||
font-family: 'DejaVu Sans', sans-serif; font-weight: 400;
|
||||
border: 0;
|
||||
}
|
||||
input[type="button"]:hover,
|
||||
input[type="submit"]:hover,
|
||||
|
|
|
@ -91,6 +91,8 @@
|
|||
<div>{{ form.submit(class_="bg-green") }}</div>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<form action="{{ url_for('adm_edit_account', user_id=user.id) }}" method="post">
|
||||
{{ trophy_form.hidden_tag() }}
|
||||
<h2>Trophées</h2>
|
||||
|
@ -99,7 +101,7 @@
|
|||
{% if id[0] == "t" %}
|
||||
<div>
|
||||
{# TODO: add trophies icons #}
|
||||
{{ input(checked=id in trophy_form.user_trophies) }}
|
||||
{{ input(checked=id in user_owned) }}
|
||||
{{ input.label }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -108,6 +110,8 @@
|
|||
<div>{{ trophy_form.submit(class_="bg-green") }}</div>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2 style="margin-top:30px;">Supprimer le compte</h2>
|
||||
<a href="{{ url_for('adm_delete_account', user_id=user.id) }}" class="button bg-red">Supprimer le compte</a>
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
{% block content %}
|
||||
<section>
|
||||
<p>Cette page présente une vue d'ensemble des titres et trophées.</p>
|
||||
<p>Cette page présente une vue d'ensemble des titres et trophées. Les
|
||||
conditions d'obtention exactes des trophées sont définies dans le code et
|
||||
non dans la base de données.</p>
|
||||
|
||||
<h2>Titres et trophées</h2>
|
||||
|
||||
|
@ -20,8 +22,8 @@
|
|||
<td style="{{ trophy.css }}">{{ trophy.name }}</td>
|
||||
<td>{{ trophy | is_title }}</td>
|
||||
<td><code>{{ trophy.css }}</code></td>
|
||||
<td><a href="{{ url_for('adm_edit_trophy', trophy_id=trophy.id) }}">Modifier</a></td>
|
||||
<td><a href="{{ url_for('adm_delete_trophy', trophy_id=trophy.id) }}">Supprimer</a></td>
|
||||
<td style="text-align: center"><a href="{{ url_for('adm_edit_trophy', trophy_id=trophy.id) }}">Modifier</a></td>
|
||||
<td style="text-align: center"><a href="{{ url_for('adm_delete_trophy', trophy_id=trophy.id) }}">Supprimer</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
136
master.py
136
master.py
|
@ -3,17 +3,26 @@
|
|||
from app import app, db
|
||||
from app.models.users import Member, Group, GroupPrivilege
|
||||
from app.models.privs import SpecialPrivilege
|
||||
from app.models.trophies import Trophy, Title
|
||||
from app.models.trophies import Trophy, Title, TrophyMember
|
||||
from app.utils import unicode_names
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
import readline
|
||||
|
||||
help_msg = """
|
||||
This is the Planète Casio master shell. Type 'exit' or C-D to leave.
|
||||
|
||||
Type 'members' to see a list of members and 'groups' to see a list of groups.
|
||||
Type a category name to see a list of elements. Available categories are:
|
||||
|
||||
Type 'reset-groups-and-privs' to reset all groups and privileges to the
|
||||
'members' Registered community members
|
||||
'groups' Privilege groups
|
||||
'trophies' Trophies
|
||||
'trophy-members' Trophies owned by members
|
||||
|
||||
Type a category name followed by 'clear' to remove all entries in the category.
|
||||
|
||||
Type 'create-groups-and-privs' to recreate all groups and privileges to the
|
||||
default. This function generates a minimal set of groups and members to prepare
|
||||
the database.
|
||||
1. Deletes all groups
|
||||
|
@ -26,43 +35,88 @@ the database.
|
|||
|
||||
Type 'add-group <member> #<group-id>' to add a new member to a group.
|
||||
|
||||
Type 'reset-trophies' to reset trophies and titles.
|
||||
Type 'create-trophies' to reset trophies and titles.
|
||||
"""
|
||||
|
||||
def members():
|
||||
#
|
||||
# Category viewers
|
||||
#
|
||||
|
||||
def members(*args):
|
||||
if args == ("clear",):
|
||||
for m in Member.query.all():
|
||||
m.delete()
|
||||
db.session.commit()
|
||||
print("Removed all members.")
|
||||
return
|
||||
|
||||
for m in Member.query.all():
|
||||
print(m.name)
|
||||
print(m)
|
||||
|
||||
def groups(*args):
|
||||
if args == ("clear",):
|
||||
for g in Group.query.all():
|
||||
g.delete()
|
||||
db.session.commit()
|
||||
print("Removed all groups.")
|
||||
return
|
||||
|
||||
def groups():
|
||||
for g in Group.query.all():
|
||||
print(f"#{g.id} {g.name}")
|
||||
print(f"#{g.id} {g.name}")
|
||||
|
||||
def reset_groups_and_privs():
|
||||
def trophies(*args):
|
||||
if args == ("clear",):
|
||||
for t in Trophy.query.all():
|
||||
db.session.delete(t)
|
||||
db.session.commit()
|
||||
print("Removed all trophies.")
|
||||
return
|
||||
|
||||
for t in Trophy.query.all():
|
||||
print(t)
|
||||
|
||||
def trophy_members(*args):
|
||||
for t in Trophy.query.all():
|
||||
if t.owners == []:
|
||||
continue
|
||||
|
||||
print(t)
|
||||
for m in t.owners:
|
||||
print(f" {m}")
|
||||
|
||||
#
|
||||
# Creation and edition
|
||||
#
|
||||
|
||||
def create_groups_and_privs():
|
||||
# Clean up groups
|
||||
for g in Group.query.all():
|
||||
g.delete()
|
||||
groups("clear")
|
||||
|
||||
# Create base groups
|
||||
groups = []
|
||||
gr = []
|
||||
with open(os.path.join(app.root_path, "data", "groups.yaml")) as fp:
|
||||
groups = yaml.load(fp.read())
|
||||
gr = yaml.safe_load(fp.read())
|
||||
|
||||
for g in groups:
|
||||
for g in gr:
|
||||
g["obj"] = Group(g["name"], g["css"], g["descr"])
|
||||
db.session.add(g["obj"])
|
||||
db.session.commit()
|
||||
|
||||
for g in groups:
|
||||
for g in gr:
|
||||
for priv in g.get("privs", "").split():
|
||||
db.session.add(GroupPrivilege(g["obj"], priv))
|
||||
db.session.commit()
|
||||
|
||||
print(f"Created {len(gr)} groups.")
|
||||
|
||||
# Clean up test members
|
||||
for name in "PlanèteCasio GLaDOS".split():
|
||||
m = Member.query.filter_by(name=name).first()
|
||||
if m is not None:
|
||||
m.delete()
|
||||
|
||||
print("Removed test members.")
|
||||
|
||||
# Create template members
|
||||
|
||||
def addgroup(member, group):
|
||||
|
@ -70,11 +124,11 @@ def reset_groups_and_privs():
|
|||
if g is not None:
|
||||
member.groups.append(g)
|
||||
|
||||
m = Member('PlanèteCasio', 'contact@planet-casio.com', 'v5-forever')
|
||||
m = Member("PlanèteCasio", "contact@planet-casio.com", "v5-forever")
|
||||
addgroup(m, "Compte communautaire")
|
||||
db.session.add(m)
|
||||
|
||||
m = Member('GLaDOS', 'glados@aperture.science', 'v5-forever')
|
||||
m = Member("GLaDOS", "glados@aperture.science", "v5-forever")
|
||||
m.xp = 1338
|
||||
addgroup(m, "Robot")
|
||||
db.session.add(m)
|
||||
|
@ -85,39 +139,50 @@ def reset_groups_and_privs():
|
|||
|
||||
db.session.commit()
|
||||
|
||||
print(f"Created 2 test members with some privileges.")
|
||||
|
||||
def reset_trophies():
|
||||
|
||||
def create_trophies():
|
||||
# Clean up trophies
|
||||
for t in Trophy.query.all():
|
||||
db.session.delete(t)
|
||||
trophies("clear")
|
||||
|
||||
# Create base trophies
|
||||
trophies = []
|
||||
tr = []
|
||||
with open(os.path.join(app.root_path, "data", "trophies.yaml")) as fp:
|
||||
trophies = yaml.load(fp.read())
|
||||
tr = yaml.safe_load(fp.read())
|
||||
|
||||
for t in trophies:
|
||||
for t in tr:
|
||||
if t["is_title"]:
|
||||
t["obj"] = Title(t["name"], t.get("css", ""))
|
||||
trophy = Title(t["name"], t.get("css", ""))
|
||||
else:
|
||||
t["obj"] = Trophy(t["name"])
|
||||
db.session.add(t["obj"])
|
||||
trophy = Trophy(t["name"])
|
||||
db.session.add(trophy)
|
||||
db.session.commit()
|
||||
|
||||
print(f"Created {len(tr)} trophies.")
|
||||
|
||||
def add_group(member, group):
|
||||
if group[0] != '#':
|
||||
print("error: group id should start with '#'.")
|
||||
if group[0] != "#":
|
||||
print(f"error: group id {group} should start with '#'")
|
||||
return
|
||||
gid = int(group[1:])
|
||||
|
||||
norm = unicode_names.normalize(member)
|
||||
|
||||
g = Group.query.filter_by(id=gid).first()
|
||||
m = Member.query.filter_by(name=member).first()
|
||||
m = Member.query.filter_by(norm=norm).first()
|
||||
|
||||
if m is None:
|
||||
print(f"error: no member has a normalized name of '{norm}'")
|
||||
return
|
||||
|
||||
m.groups.append(g)
|
||||
db.session.add(m)
|
||||
db.session.commit()
|
||||
|
||||
#
|
||||
# Main program
|
||||
#
|
||||
|
||||
print(help_msg)
|
||||
|
||||
|
@ -125,20 +190,23 @@ commands = {
|
|||
"exit": lambda: sys.exit(0),
|
||||
"members": members,
|
||||
"groups": groups,
|
||||
"reset-groups-and-privs": reset_groups_and_privs,
|
||||
"reset-trophies": reset_trophies,
|
||||
"trophies": trophies,
|
||||
"trophy-members": trophy_members,
|
||||
"create-groups-and-privs": create_groups_and_privs,
|
||||
"create-trophies": create_trophies,
|
||||
"add-group": add_group,
|
||||
}
|
||||
|
||||
while True:
|
||||
try:
|
||||
print('> ', end='')
|
||||
print("@> ", end="")
|
||||
cmd = input().split()
|
||||
except EOFError:
|
||||
sys.exit(0)
|
||||
|
||||
if not cmd: continue
|
||||
if not cmd:
|
||||
continue
|
||||
if cmd[0] not in commands:
|
||||
print("error: unknown command.")
|
||||
print(f"error: unknown command '{cmd[0]}'")
|
||||
else:
|
||||
commands[cmd[0]](*cmd[1:])
|
||||
|
|
Loading…
Reference in New Issue