From 79e3189f4b250ab8f7b214baedd8d2ebe46778ec Mon Sep 17 00:00:00 2001 From: Darks Date: Thu, 6 Jun 2019 23:24:14 +0200 Subject: [PATCH 1/2] First draw for trophies --- app/__init__.py | 2 +- app/forms/account.py | 19 ++----- app/forms/trophies.py | 12 ++++ app/models/trophies.py | 37 ++++++++++++ app/models/users.py | 4 +- app/routes/admin/account.py | 4 +- app/routes/admin/index.py | 2 +- app/routes/admin/trophies.py | 29 ++++++++++ app/templates/admin/index.html | 1 + app/templates/admin/trophies.html | 56 +++++++++++++++++++ config.py | 1 + ...61d7b7a7ea_ajout_des_titres_et_trophées.py | 47 ++++++++++++++++ 12 files changed, 195 insertions(+), 19 deletions(-) create mode 100644 app/forms/trophies.py create mode 100644 app/models/trophies.py create mode 100644 app/routes/admin/trophies.py create mode 100644 app/templates/admin/trophies.html create mode 100644 migrations/versions/c961d7b7a7ea_ajout_des_titres_et_trophées.py diff --git a/app/__init__.py b/app/__init__.py index 47625cc..b101104 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -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 diff --git a/app/forms/account.py b/app/forms/account.py index fcfb0df..aff6f92 100644 --- a/app/forms/account.py +++ b/app/forms/account.py @@ -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()]) diff --git a/app/forms/trophies.py b/app/forms/trophies.py new file mode 100644 index 0000000..626be35 --- /dev/null +++ b/app/forms/trophies.py @@ -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') diff --git a/app/models/trophies.py b/app/models/trophies.py new file mode 100644 index 0000000..104855a --- /dev/null +++ b/app/models/trophies.py @@ -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'))) diff --git a/app/models/users.py b/app/models/users.py index b1096fa..6dfbbc4 100644 --- a/app/models/users.py +++ b/app/models/users.py @@ -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): diff --git a/app/routes/admin/account.py b/app/routes/admin/account.py index 4311686..53d1bbb 100644 --- a/app/routes/admin/account.py +++ b/app/routes/admin/account.py @@ -7,7 +7,7 @@ from app import app, db @app.route('/admin/edit-account/', 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//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() diff --git a/app/routes/admin/index.py b/app/routes/admin/index.py index 5ef458e..bd0c7cc 100644 --- a/app/routes/admin/index.py +++ b/app/routes/admin/index.py @@ -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') diff --git a/app/routes/admin/trophies.py b/app/routes/admin/trophies.py new file mode 100644 index 0000000..42b76c9 --- /dev/null +++ b/app/routes/admin/trophies.py @@ -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) diff --git a/app/templates/admin/index.html b/app/templates/admin/index.html index 7ea09d0..f4f37ee 100644 --- a/app/templates/admin/index.html +++ b/app/templates/admin/index.html @@ -9,6 +9,7 @@

Pages générales du panneau d'administration :

{% endblock %} diff --git a/app/templates/admin/trophies.html b/app/templates/admin/trophies.html new file mode 100644 index 0000000..5c5434b --- /dev/null +++ b/app/templates/admin/trophies.html @@ -0,0 +1,56 @@ +{% extends "base/base.html" %} + +{% block title %} +Panneau d'administration »

Titres et trophées

+{% endblock %} + +{% block content %} +
+

Cette page présente une vue d'ensemble des titres et trophées.

+ +

Titres et trophées

+ + + + + {% for trophy in trophies %} + + + + + + {% endfor %} +
IcôneNomTitreModifier
{{ trophy.name }}{{ trophy.name }}{{ trophy.title }}Modifier
+
+ +
+
+ {{ form.hidden_tag() }} +

Nouveau trophée

+ +
+ {{ form.name.label }} + {{ form.name }} + {% for error in form.name.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.is_title.label }} + {{ form.is_title }} +
{{ form.is_title.description }}
+ {% for error in form.is_title.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.title.label }} + {{ form.title }} +
{{ form.title.description }}
+ {% for error in form.title.errors %} + {{ error }} + {% endfor %} +
+
{{ form.submit(class_="bg-green") }}
+
+{% endblock %} diff --git a/config.py b/config.py index bf71675..85eb3ba 100644 --- a/config.py +++ b/config.py @@ -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): diff --git a/migrations/versions/c961d7b7a7ea_ajout_des_titres_et_trophées.py b/migrations/versions/c961d7b7a7ea_ajout_des_titres_et_trophées.py new file mode 100644 index 0000000..964c42e --- /dev/null +++ b/migrations/versions/c961d7b7a7ea_ajout_des_titres_et_trophées.py @@ -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 ### From f67129a36b4466b013579bfa926ac514388f3d42 Mon Sep 17 00:00:00 2001 From: Darks Date: Fri, 7 Jun 2019 01:44:04 +0200 Subject: [PATCH 2/2] =?UTF-8?q?Ajout=20des=20troph=C3=A9es=20et=20du=20pan?= =?UTF-8?q?el=20pour=20les=20g=C3=A9rer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/forms/trophies.py | 14 +++-- app/models/trophies.py | 8 ++- app/routes/admin/account.py | 4 +- app/routes/admin/trophies.py | 60 ++++++++++++++++--- app/templates/admin/delete_trophy.html | 28 +++++++++ app/templates/admin/edit_trophy.html | 38 ++++++++++++ app/templates/admin/trophies.html | 37 ++++++------ app/utils/validators.py | 20 ++++++- ...59d74cf54_update_des_titres_et_trophées.py | 30 ++++++++++ 9 files changed, 202 insertions(+), 37 deletions(-) create mode 100644 app/templates/admin/delete_trophy.html create mode 100644 app/templates/admin/edit_trophy.html create mode 100644 migrations/versions/6ae59d74cf54_update_des_titres_et_trophées.py diff --git a/app/forms/trophies.py b/app/forms/trophies.py index 626be35..49535ba 100644 --- a/app/forms/trophies.py +++ b/app/forms/trophies.py @@ -1,12 +1,16 @@ from flask_wtf import FlaskForm -from wtforms import StringField, BooleanField, SubmitField +from wtforms import StringField, SubmitField, BooleanField from wtforms.validators import DataRequired, Optional from flask_wtf.file import FileField # Cuz' wtforms' FileField is shitty -class CreateTrophyForm(FlaskForm): +class TrophyForm(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') + title = StringField('Titre', description='Titre affiché dans le cas échéant. Laisser vide pour un simple trophée.', validators=[Optional()]) + css = StringField('CSS', description='CSS appliqué au titre, le cas échéant.') + submit = SubmitField('Envoyer') + +class DeleteTrophyForm(FlaskForm): + delete = BooleanField('Confirmer la suppression', validators=[DataRequired()], description='Attention, cette opération est irréversible !') + submit = SubmitField('Supprimer le trophée') diff --git a/app/models/trophies.py b/app/models/trophies.py index 104855a..6a56d25 100644 --- a/app/models/trophies.py +++ b/app/models/trophies.py @@ -11,7 +11,7 @@ class Trophy(db.Model): 'polymorphic_on': type } # Standalone properties - name = db.Column(db.Text(convert_unicode=True)) + name = db.Column(db.Unicode(64), index=True) owners = db.relationship('Member', secondary=lambda: TrophyMember, back_populates='trophies') @@ -24,11 +24,13 @@ class Title(Trophy): __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)) + title = db.Column(db.Unicode(64)) + css = db.Column(db.Text(convert_unicode=True)) - def __init__(self, name, title): + def __init__(self, name, title, css): self.name = name self.title = title + self.css = css # Many-to-many relation for users earning trophies diff --git a/app/routes/admin/account.py b/app/routes/admin/account.py index 53d1bbb..55a400b 100644 --- a/app/routes/admin/account.py +++ b/app/routes/admin/account.py @@ -6,7 +6,7 @@ from app.utils.render import render from app import app, db -@app.route('/admin/edit-account/', methods=['GET', 'POST']) +@app.route('/admin/account//edit', methods=['GET', 'POST']) @priv_required('access-admin-panel', 'edit-account') def adm_edit_account(user_id): user = Member.query.filter_by(id=user_id).first_or_404() @@ -42,7 +42,7 @@ def adm_edit_account(user_id): return render('admin/edit_account.html', user=user, form=form) -@app.route('/admin/edit-account//delete', methods=['GET', 'POST']) +@app.route('/admin/account//delete', methods=['GET', 'POST']) @priv_required('access-admin-panel', 'delete-account') def adm_delete_account(user_id): user = Member.query.filter_by(id=user_id).first_or_404() diff --git a/app/routes/admin/trophies.py b/app/routes/admin/trophies.py index 42b76c9..dda263c 100644 --- a/app/routes/admin/trophies.py +++ b/app/routes/admin/trophies.py @@ -1,29 +1,71 @@ -from flask import request, flash +from flask import request, flash, redirect, url_for from app.utils.priv_required import priv_required from app.models.trophies import Trophy, Title -from app.forms.trophies import CreateTrophyForm +from app.forms.trophies import TrophyForm, DeleteTrophyForm from app.utils.render import render from app import app, db @app.route('/admin/trophies', methods=['GET', 'POST']) -@priv_required('access-admin-panel', ) +@priv_required('access-admin-panel', 'edit-trophies') def adm_trophies(): - form = CreateTrophyForm() + form = TrophyForm() if request.method == "POST": if form.validate_on_submit(): - if form.is_title.data: - trophy = Title(form.name.data, form.title.data) - type = 'titre' + is_title = form.title.data != "" + if is_title: + trophy = Title(form.name.data, form.title.data, form.css.data) else: trophy = Trophy(form.name.data) - type = 'trophée' db.session.add(trophy) db.session.commit() - flash(f'Nouveau {type} ajoutée', 'ok') + flash(f'Nouveau {["trophée", "titre"][is_title]} ajouté', '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) + + +@app.route('/admin/trophies//edit', methods=['GET', 'POST']) +@priv_required('access-admin-panel', 'edit-trophies') +def adm_edit_trophy(trophy_id): + trophy = Trophy.query.filter_by(id=trophy_id).first_or_404() + + form = TrophyForm() + if request.method == "POST": + if form.validate_on_submit(): + is_title = form.title.data != "" + if is_title: + trophy.name = form.name.data + trophy.title = form.title.data + trophy.css = form.css.data + else: + trophy.name = form.name.data + db.session.merge(trophy) + db.session.commit() + flash(f'{["Trophée", "Titre"][is_title]} modifié', 'ok') + return redirect(url_for('adm_trophies')) + else: + flash('Erreur lors de la création du trophée', 'error') + return render('admin/edit_trophy.html', trophy=trophy, form=form) + + +@app.route('/admin/trophies//delete', methods=['GET', 'POST']) +@priv_required('access-admin-panel', 'edit-trophies') +def adm_delete_trophy(trophy_id): + trophy = Trophy.query.filter_by(id=trophy_id).first_or_404() + + # TODO: Add an overview of what will be deleted. + del_form = DeleteTrophyForm() + if request.method == "POST": + if del_form.validate_on_submit(): + db.session.delete(trophy) + db.session.commit() + flash('Trophée supprimé', 'ok') + return redirect(url_for('adm_trophies')) + else: + flash('Erreur lors de la suppression du trophée', 'error') + del_form.delete.data = False # Force to tick to delete the account + return render('admin/delete_trophy.html', trophy=trophy, del_form=del_form) diff --git a/app/templates/admin/delete_trophy.html b/app/templates/admin/delete_trophy.html new file mode 100644 index 0000000..1ae2813 --- /dev/null +++ b/app/templates/admin/delete_trophy.html @@ -0,0 +1,28 @@ +{% extends "base/base.html" %} + +{% block title %} +Panneau d'administration » Titres et trophées »

Suppression du trophée '{{ trophy.name }}'

+{% endblock %} + +{% block content %} +
+

Confirmer la suppression du trophée

+

Le trophée '{{ trophy.name }}' que vous allez supprimer est lié à :

+
    +
  • {{ trophy.owners | length }} membre{{ trophy.owners|length|pluralize }}
  • +
+ + + {{ del_form.hidden_tag() }} +
+ {{ del_form.delete.label }} + {{ del_form.delete(checked=False) }} +
{{ del_form.delete.description }}
+ {% for error in del_form.delete.errors %} + {{ error }} + {% endfor %} +
+
{{ del_form.submit(class_="bg-red") }}
+ +
+{% endblock %} diff --git a/app/templates/admin/edit_trophy.html b/app/templates/admin/edit_trophy.html new file mode 100644 index 0000000..83aacd9 --- /dev/null +++ b/app/templates/admin/edit_trophy.html @@ -0,0 +1,38 @@ +{% extends "base/base.html" %} + +{% block title %} +Panneau d'administration » Titres et trophées »

Édition du trophée '{{ trophy.name }}'

+{% endblock %} + +{% block content %} +
+
+ {{ form.hidden_tag() }} +

Éditer le trophée

+ +
+ {{ form.name.label }} + {{ form.name(value=trophy.name) }} + {% for error in form.name.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.title.label }} + {{ form.title(value=trophy.title) }} +
{{ form.title.description }}
+ {% for error in form.title.errors %} + {{ error }} + {% endfor %} +
+
+ {{ form.css.label }} + {{ form.css(value=trophy.css) }} +
{{ form.css.description }}
+ {% for error in form.css.errors %} + {{ error }} + {% endfor %} +
+
{{ form.submit(class_="bg-green") }}
+
+{% endblock %} diff --git a/app/templates/admin/trophies.html b/app/templates/admin/trophies.html index 5c5434b..80e628f 100644 --- a/app/templates/admin/trophies.html +++ b/app/templates/admin/trophies.html @@ -11,13 +11,17 @@

Titres et trophées

- + + {% for trophy in trophies %} - + + - - + + + + {% endfor %}
IcôneNomTitreModifier
idIcôneNomTitreStyleModifierSupprimer
{{ trophy.name }}
{{ trophy.id }}{{ trophy.name }} {{ trophy.name }}{{ trophy.title }}Modifier{{ trophy.title }}{{ trophy.css }}ModifierSupprimer
@@ -27,30 +31,29 @@ {{ form.hidden_tag() }}

Nouveau trophée

- -
+
{{ form.name.label }} {{ form.name }} {% for error in form.name.errors %} {{ error }} {% endfor %}
-
- {{ form.is_title.label }} - {{ form.is_title }} -
{{ form.is_title.description }}
- {% for error in form.is_title.errors %} - {{ error }} - {% endfor %} -
-
+
{{ form.title.label }} {{ form.title }} -
{{ form.title.description }}
+
{{ form.title.description }}
{% for error in form.title.errors %} {{ error }} {% endfor %}
-
{{ form.submit(class_="bg-green") }}
+
+ {{ form.css.label }} + {{ form.css }} +
{{ form.css.description }}
+ {% for error in form.css.errors %} + {{ error }} + {% endfor %} +
+
{{ form.submit(class_="bg-green") }}
{% endblock %} diff --git a/app/utils/validators.py b/app/utils/validators.py index a922f38..5705f1c 100644 --- a/app/utils/validators.py +++ b/app/utils/validators.py @@ -1,6 +1,6 @@ from flask_login import current_user from wtforms.validators import ValidationError -from app.models.users import User, Member +from app.models.users import Member from app.utils.valid_name import valid_name from app.utils.unicode_names import normalize from config import V5Config @@ -65,3 +65,21 @@ def old_password(form, field): raise ValidationError('Votre ancien mot de passe est requis pour cette modification.') if not current_user.check_password(form.old_password.data): raise ValidationError('Mot de passe actuel erroné.') + + +def id_exists(object): + """Check if an id exists in a table""" + def _id_exists(form, id): + try: + id = int(id.data) + except ValueError: + raise ValidationError('L\'id n\'est pas un entier valide') + r = object.query.filter_by(id=id) + if not r: + raise ValidationError('L\'id n\'existe pas dans la BDD') + return _id_exists + + +def css(form, css): + """Check if input is valid and sane CSS""" + pass diff --git a/migrations/versions/6ae59d74cf54_update_des_titres_et_trophées.py b/migrations/versions/6ae59d74cf54_update_des_titres_et_trophées.py new file mode 100644 index 0000000..93ceafc --- /dev/null +++ b/migrations/versions/6ae59d74cf54_update_des_titres_et_trophées.py @@ -0,0 +1,30 @@ +"""Update des titres et trophées + +Revision ID: 6ae59d74cf54 +Revises: c961d7b7a7ea +Create Date: 2019-06-06 23:34:53.521239 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '6ae59d74cf54' +down_revision = 'c961d7b7a7ea' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('title', sa.Column('css', sa.Text(_expect_unicode=True), nullable=True)) + op.create_index(op.f('ix_trophy_name'), 'trophy', ['name'], unique=False) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_trophy_name'), table_name='trophy') + op.drop_column('title', 'css') + # ### end Alembic commands ###