program: add metadata and a basic model for events (#114)

This commit adds most of the optional metadata for programs. The event
related to the program's publication is an actual relationship to an
Event model. The idea is to expand on that model in the future to
include:

- A link to the event's main topic
- List of programs published in the event
- Possibly, a list of all related topics (announcement, start, results,
  etc) all sharing a common 1-line header so they are linked together
- This would be used for event-related trophies
- And possibly for an event calendar
This commit is contained in:
Lephe 2022-06-16 17:00:59 +01:00
parent 8ff21c615d
commit 417fc05d29
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
6 changed files with 89 additions and 71 deletions

View File

@ -5,3 +5,4 @@ from app.models.topic import Topic
from app.models.notification import Notification
from app.models.program import Program
from app.models.tag import Tag
from app.models.event import Event

11
app/models/event.py Normal file
View File

@ -0,0 +1,11 @@
from app import db
class Event(db.Model):
__tablename__ = 'event'
id = db.Column(db.Integer, primary_key=True)
# Pretty event name, eg. "CPC #28"
name = db.Column(db.Unicode(128))
# Main topic, used to automatically insert links
main_topic = db.Column(db.Integer, db.ForeignKey('topic.id'))

View File

@ -10,10 +10,21 @@ class Program(Post):
# Program name
name = db.Column(db.Unicode(128))
# Author, when different from the poster
real_author = db.Column(db.Unicode(128))
# Version
version = db.Column(db.Unicode(64))
# Approximate size as indicated by poster
size = db.Column(db.Unicode(64))
# License identifier
license = db.Column(db.String(32))
# TODO: Category (games/utilities/lessons)
# TODO: Compatible calculator models
# TODO: Number of views, statistics, etc
# Label de qualité
label = db.Column(db.Boolean, nullable=False, server_default="FALSE")
# Event for which the program was posted
event = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=True)
# TODO: Number of views and downloads
# Thread with the program description (top comment) and comments
thread_id = db.Column(db.Integer,db.ForeignKey('thread.id'),nullable=False)

View File

@ -17,12 +17,19 @@
<h2>Tous les programmes</h2>
<table class=programlist>
<tr><th>ID</th><th>Nom</th><th>Auteur</th><th>Publié le</th><th>Progrank</th><th>Tags</th></tr>
<tr><th>ID</th><th>Nom</th><th>Auteur</th><th>Label</th><th>Progrank</th><th>Tags</th></tr>
{% for p in programs %}
<tr><td>{{ p.id }}</td>
<td><a href='{{ url_for("program_view", page=(p,1)) }}'>{{ p.name }}</a></td>
<td>{{ p.author.name }}</td>
<td>
{%- if p.real_author -%}
{{ p.real_author }} (posté par <a href='{{ url_for("user", username=p.author.name) }}'>{{ p.author.name }}</a>)
{%- else -%}
<a href='{{ url_for("user", username=p.author.name) }}'>{{ p.author.name }}</a>
{%- endif -%}
</td>
<td>{{ p.date_created | dyndate }}</td>
<td>{{ "Oui" if p.label else "Non" }}</td>
<td><span title="Dernière mise à jour : {{ p.progrank_date | dyndate }}">{{ p.progrank }}</span></td>
<td>
{%- for tag in p.tags %}

View File

@ -12,78 +12,18 @@
{% block content %}
<section>
<div style="display:flex;flex-wrap:wrap;align-items:center;">
<div>
{{ widget_user.profile(p.author) }}
</div>
<div style="padding:30px;">
<div style="font-size:115%;font-style:italic;margin-bottom:15px;">
{{ p.title }}
</div>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae
feugiat ante. Pellentesque luctus lorem tincidunt vestibulum condimentum.
Nullam sed tempus sem. Phasellus quis diam vitae sapien luctus consequat
ac eget lacus. Sed rutrum condimentum sagittis. Nullam erat nibh, euismod
ac metus at, consequat tincidunt ipsum. Fusce sagittis iaculis orci sedporta.
Etiam bibendum purus et ipsum pellentesque, quis sodales libero congue. Nunc
lectus quam, cursus non dictum nec, volutpat eget felis. Praesent sollicitudin
massa erat, nec venenatis lorem lacinia et. Etiam ullamcorper neque quis
nisi sodales vulputate. Integer scelerisque luctus arcu, ut elementum justo
auctor a. Praesent sit amet libero risus.</p>
<div class="gallery">
<img src="https://www.planet-casio.com/storage/staff/IDK_3_manoir.png" alt="">
<img src="https://www.planet-casio.com/storage/staff/IDK_7_stats.png" alt="">
<video>
<source src="https://linx.breizh.pm/selif/xgh9k9sq.mp4">
</video>
<img src="https://www.planet-casio.com/storage/staff/IDK_3_manoir.png" alt="">
<img src="https://www.planet-casio.com/storage/staff/IDK_7_stats.png" alt="">
<video>
<source src="https://www.planet-casio.com/storage/staff/IDK_5_intrigue.mp4">
</video>
<img src="https://www.planet-casio.com/storage/staff/IDK_3_manoir.png" alt="">
<img src="https://www.planet-casio.com/storage/staff/IDK_7_stats.png" alt="">
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae
feugiat ante. Pellentesque luctus lorem tincidunt vestibulum condimentum.
Nullam sed tempus sem. Phasellus quis diam vitae sapien luctus consequat
ac eget lacus. Sed rutrum condimentum sagittis. Nullam erat nibh, euismod
ac metus at, consequat tincidunt ipsum. Fusce sagittis iaculis orci sedporta.
Etiam bibendum purus et ipsum pellentesque, quis sodales libero congue. Nunc
lectus quam, cursus non dictum nec, volutpat eget felis. Praesent sollicitudin
massa erat, nec venenatis lorem lacinia et. Etiam ullamcorper neque quis
nisi sodales vulputate. Integer scelerisque luctus arcu, ut elementum justo
auctor a. Praesent sit amet libero risus.</p>
<div class="gallery">
<img src="https://www.planet-casio.com/storage/staff/IDK_3_manoir.png" alt="">
<img src="https://www.planet-casio.com/storage/staff/IDK_7_stats.png" alt="">
<video>
<source src="https://linx.breizh.pm/selif/xgh9k9sq.mp4">
</video>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae
feugiat ante. Pellentesque luctus lorem tincidunt vestibulum condimentum.
Nullam sed tempus sem. Phasellus quis diam vitae sapien luctus consequat
ac eget lacus. Sed rutrum condimentum sagittis. Nullam erat nibh, euismod
ac metus at, consequat tincidunt ipsum. Fusce sagittis iaculis orci sedporta.
Etiam bibendum purus et ipsum pellentesque, quis sodales libero congue. Nunc
lectus quam, cursus non dictum nec, volutpat eget felis. Praesent sollicitudin
massa erat, nec venenatis lorem lacinia et. Etiam ullamcorper neque quis
nisi sodales vulputate. Integer scelerisque luctus arcu, ut elementum justo
auctor a. Praesent sit amet libero risus.</p>
</div>
{% if p.thread.top_comment %}
{% call widget_thread.thread_leader(p.thread.top_comment) %}
<div class="info">
<div>Posté le {{ p.date_created | dyndate }}</div>
{{ widget_thread.post_actions(p) }}
</div>
<h1>{{ p.name }}</h1>
Infos infos infos
<hr>
{{ p.thread.top_comment.text | md }}
{{ widget_attachments.attachments(p.thread.top_comment) }}
{% endcall %}

View File

@ -0,0 +1,48 @@
"""add program metadata and a base for events
Revision ID: ba47de949e59
Revises: daa5d5913ef8
Create Date: 2022-06-16 12:05:40.797694
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'ba47de949e59'
down_revision = 'daa5d5913ef8'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('event',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.Unicode(length=128), nullable=True),
sa.Column('main_topic', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['main_topic'], ['topic.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.add_column('program', sa.Column('real_author', sa.Unicode(length=128), nullable=True))
op.add_column('program', sa.Column('version', sa.Unicode(length=64), nullable=True))
op.add_column('program', sa.Column('size', sa.Unicode(length=64), nullable=True))
op.add_column('program', sa.Column('license', sa.String(length=32), nullable=True))
op.add_column('program', sa.Column('label', sa.Boolean(), server_default='FALSE', nullable=False))
op.add_column('program', sa.Column('event', sa.Integer(), nullable=True))
op.create_foreign_key(None, 'program', 'event', ['event'], ['id'])
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'program', type_='foreignkey')
op.drop_column('program', 'event')
op.drop_column('program', 'label')
op.drop_column('program', 'license')
op.drop_column('program', 'size')
op.drop_column('program', 'version')
op.drop_column('program', 'real_author')
op.drop_table('event')
# ### end Alembic commands ###