First draw for trophies

This commit is contained in:
Darks 2019-06-06 23:24:14 +02:00
parent d6e8f7d4d8
commit 79e3189f4b
Signed by: Darks
GPG Key ID: F61F10FA138E797C
12 changed files with 195 additions and 19 deletions

View File

@ -16,5 +16,5 @@ login.login_message = "Veuillez vous authentifier avant de continuer."
from app import models # IDK why this is here, but it works
from app.routes import index, search, users # To load routes at initialization
from app.routes.account import login, account
from app.routes.admin import index, groups, account
from app.routes.admin import index, groups, account, trophies
from app.utils import pluralize # To use pluralize into the templates

View File

@ -36,20 +36,11 @@ 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])
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])
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()])
birthday = DateField('Anniversaire', validators=[Optional()])
signature = TextAreaField('Signature', validators=[Optional()])

12
app/forms/trophies.py Normal file
View File

@ -0,0 +1,12 @@
from flask_wtf import FlaskForm
from wtforms import StringField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Optional
from flask_wtf.file import FileField # Cuz' wtforms' FileField is shitty
class CreateTrophyForm(FlaskForm):
name = StringField('Nom', validators=[DataRequired()])
icon = FileField('Icone')
is_title = BooleanField('Le trophée est aussi un titre')
title = StringField('Titre', description='Titre affiché dans le cas échéant', validators=[Optional()])
submit = SubmitField('Créer le trophée')

37
app/models/trophies.py Normal file
View File

@ -0,0 +1,37 @@
from app import db
class Trophy(db.Model):
__tablename__ = 'trophy'
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
name = db.Column(db.Text(convert_unicode=True))
owners = db.relationship('Member', secondary=lambda: TrophyMember,
back_populates='trophies')
def __init__(self, name):
self.name = name
class Title(Trophy):
__tablename__ = 'title'
__mapper_args__ = {'polymorphic_identity': __tablename__}
id = db.Column(db.Integer, db.ForeignKey('trophy.id'), primary_key=True)
title = db.Column(db.Text(convert_unicode=True))
def __init__(self, name, title):
self.name = name
self.title = title
# Many-to-many relation for users earning trophies
TrophyMember = db.Table('trophy_member', db.Model.metadata,
db.Column('tid', db.Integer, db.ForeignKey('trophy.id')),
db.Column('uid', db.Integer, db.ForeignKey('member.id')))

View File

@ -4,6 +4,7 @@ from flask_login import UserMixin
from app.models.contents import Content
from app.models.privs import SpecialPrivilege, Group, GroupMember, \
GroupPrivilege
from app.models.trophies import Trophy, TrophyMember
import app.utils.unicode_names as unicode_names
from config import V5Config
@ -90,7 +91,8 @@ class Member(User, db.Model):
newsletter = db.Column(db.Boolean, default=False)
# Relations
# trophies = db.relationship('Trophy', back_populates='member')
trophies = db.relationship('Trophy', secondary=TrophyMember,
back_populates='owners')
# tests = db.relationship('Test', back_populates='author')
def __init__(self, name, email, password):

View File

@ -7,7 +7,7 @@ from app import app, db
@app.route('/admin/edit-account/<user_id>', methods=['GET', 'POST'])
@priv_required('edit-account')
@priv_required('access-admin-panel', 'edit-account')
def adm_edit_account(user_id):
user = Member.query.filter_by(id=user_id).first_or_404()
@ -43,7 +43,7 @@ def adm_edit_account(user_id):
@app.route('/admin/edit-account/<user_id>/delete', methods=['GET', 'POST'])
@priv_required('delete-account')
@priv_required('access-admin-panel', 'delete-account')
def adm_delete_account(user_id):
user = Member.query.filter_by(id=user_id).first_or_404()

View File

@ -3,7 +3,7 @@ from app.utils.render import render
from app import app
@app.route('/admin', methods=['GET', 'POST'])
@app.route('/admin', methods=['GET'])
@priv_required('access-admin-panel')
def adm():
return render('admin/index.html')

View File

@ -0,0 +1,29 @@
from flask import request, flash
from app.utils.priv_required import priv_required
from app.models.trophies import Trophy, Title
from app.forms.trophies import CreateTrophyForm
from app.utils.render import render
from app import app, db
@app.route('/admin/trophies', methods=['GET', 'POST'])
@priv_required('access-admin-panel', )
def adm_trophies():
form = CreateTrophyForm()
if request.method == "POST":
if form.validate_on_submit():
if form.is_title.data:
trophy = Title(form.name.data, form.title.data)
type = 'titre'
else:
trophy = Trophy(form.name.data)
type = 'trophée'
db.session.add(trophy)
db.session.commit()
flash(f'Nouveau {type} ajoutée', 'ok')
else:
flash('Erreur lors de la création du trophée', 'error')
trophies = Trophy.query.all()
return render('admin/trophies.html', trophies=trophies,
form=form)

View File

@ -9,6 +9,7 @@
<p>Pages générales du panneau d'administration :</p>
<ul>
<li><a href="{{ url_for('adm_groups') }}">Groupes et privilèges</a></li>
<li><a href="{{ url_for('adm_trophies') }}">Titres et trophées</a></li>
</ul>
</section>
{% endblock %}

View File

@ -0,0 +1,56 @@
{% extends "base/base.html" %}
{% block title %}
<a href="{{ url_for('adm') }}">Panneau d'administration</a> » <h1>Titres et trophées</h1>
{% endblock %}
{% block content %}
<section>
<p>Cette page présente une vue d'ensemble des titres et trophées.</p>
<h2>Titres et trophées</h2>
<table style="width:90%; margin: auto;">
<tr><th>Icône</th><th>Nom</th><th>Titre</th><th>Modifier</th></tr>
{% for trophy in trophies %}
<tr><td><img src="#" alt="{{ trophy.name }}"></td>
<td>{{ trophy.name }}</td>
<td>{{ trophy.title }}</td>
<td><a href="{# {{ url_for('adm_edit_trophy', trophy_id=trophy.id) }} #}">Modifier</a></td>
</tr>
{% endfor %}
</table>
</section>
<section class="form">
<form action="{{ url_for('adm_trophies') }}" method="post" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<h2>Nouveau trophée</h2>
<div>
{{ form.name.label }}
{{ form.name }}
{% for error in form.name.errors %}
<span class="msgerror">{{ error }}</span>
{% endfor %}
</div>
<div>
{{ form.is_title.label }}
{{ form.is_title }}
<div class=desc>{{ form.is_title.description }}</div>
{% for error in form.is_title.errors %}
<span class="msgerror">{{ error }}</span>
{% endfor %}
</div>
<div>
{{ form.title.label }}
{{ form.title }}
<div class=desc>{{ form.title.description }}</div>
{% for error in form.title.errors %}
<span class="msgerror">{{ error }}</span>
{% endfor %}
</div>
<div>{{ form.submit(class_="bg-green") }}</div>
</section>
{% endblock %}

View File

@ -7,6 +7,7 @@ class Config(object):
'postgresql+psycopg2://' + os.environ.get('USER') + ':@/pcv5'
SQLALCHEMY_TRACK_MODIFICATIONS = False
UPLOAD_FOLDER = './app/static/avatars'
LOGIN_DISABLED = True
class V5Config(object):

View File

@ -0,0 +1,47 @@
"""Ajout des titres et trophées
Revision ID: c961d7b7a7ea
Revises: a6e89f3510d9
Create Date: 2019-06-06 15:18:09.893001
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'c961d7b7a7ea'
down_revision = 'a6e89f3510d9'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('trophy',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('type', sa.String(length=20), nullable=True),
sa.Column('name', sa.Text(_expect_unicode=True), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('title',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('title', sa.Text(_expect_unicode=True), nullable=True),
sa.ForeignKeyConstraint(['id'], ['trophy.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('trophy_member',
sa.Column('tid', sa.Integer(), nullable=True),
sa.Column('uid', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['tid'], ['trophy.id'], ),
sa.ForeignKeyConstraint(['uid'], ['member.id'], )
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('trophy_member')
op.drop_table('title')
op.drop_table('trophy')
# ### end Alembic commands ###