Compare commits

...

2 Commits

Author SHA1 Message Date
Darks a5d2efab4c
WIP 2020-11-14 00:58:13 +01:00
Darks 243ae43783
dev: added support for local development test files 2020-11-13 01:45:55 +01:00
6 changed files with 92 additions and 9 deletions

4
.gitignore vendored
View File

@ -5,7 +5,7 @@ app/static/avatars/
app/static/images/trophies/
# Development files
## Development files
# Flask env
.env
@ -17,6 +17,8 @@ venv/
# pipenv
Pipfile
Pipfile.lock
# Tests files
test.*
## Deployment files

View File

@ -18,9 +18,7 @@ class Comment(Post):
thread = db.relationship('Thread',
backref=backref('comments', lazy='dynamic'),
foreign_keys=thread_id)
# Other fields populated automatically through relations:
# <poll> A poll attached to the comment (of class Poll)
def __init__(self, author, text, thread):
"""

View File

@ -1,6 +1,8 @@
from app import db
from enum import Enum
from sqlalchemy.orm import backref
from datetime import datetime
from collections import Counter
class PollType(Enum):
@ -17,10 +19,10 @@ class Poll(db.Model):
# Unique ID
id = db.Column(db.Integer, primary_key=True)
# Owner comment
comment_id = db.Column(db.Integer, db.ForeignKey('comment.id'))
comment = db.relationship('Comment', uselist=False, back_populates="poll",
foreign_keys=thread_id)
# Author
author_id = db.Column(db.Integer, db.ForeignKey('member.id'))
author = db.relationship('Member', backref=backref('polls'),
foreign_keys=author_id)
# Type
type = db.Column(db.Enum(PollType))
@ -41,6 +43,44 @@ class Poll(db.Model):
# Other fields populated automatically through relations:
# <answers> The list of answers (of type PollAnswer)
def __init__(self, title, choices, comment, type=PollType.SINGLE):
self.title = title
self.choices = choices
self.comment = comment
self.type = PollType.SINGLE
def delete(self):
"""Deletes a poll and its answers"""
for answer in SpecialPrivilege.query.filter_by(poll_id=self.id).all():
db.session.delete(answer)
db.session.commit()
db.session.delete(self)
db.session.commit()
# Some useful properties
@property
def ended(self):
return self.end > datetime.now()
@property
def results(self):
"""Returns a Counter populated with answers"""
r = Counter()
for answer in self.answers:
if self.type == SINGLE:
r.update([answer])
else:
r.update(answer)
return r
def has_voted(self, user):
# TODO: use ORM for this dirty request
return user in [a.author for a in self.answers]
def can_vote(self, user):
return user.is_authenticated
class PollAnswer(db.Model):
"""An answer to a poll"""
@ -52,7 +92,7 @@ class PollAnswer(db.Model):
# Poll
poll_id = db.Column(db.Integer, db.ForeignKey('poll.id'))
poll = db.relationship('Poll', back_populates="answers",
poll = db.relationship('Poll', backref=backref('answers'),
foreign_keys=poll_id)
# Author. Must be Member

View File

@ -121,6 +121,7 @@ class Member(User):
# Other fields populated automatically through relations:
# <notifications> List of unseen notifications (of type Notification)
# <polls> Polls created by the member (of class Poll)
def __init__(self, name, email, password):
"""Register a new user."""

View File

@ -8,3 +8,8 @@ from app.routes.forum import index, topic
from app.routes.programs import index
from app.routes.posts import edit
from app.routes.api import markdown
try:
from app.routes import test
except ImportError:
pass

View File

@ -0,0 +1,37 @@
{% macro poll(p) %}
<div class="poll">
<p><strong>{{ p.title }}</strong></p>
{# Poll has ended: display results #}
{% if p.ended %}
<table>
{% for choice, votes in p.results.most_common() %}
<tr>
<td><label for="{{ poll.id }}-{{ loop.index }}">{{ choice }}</label></td>
<td>
<progress id="{{ poll.id }}-{{ loop.index }}" value="{{ votes }}" max="{{ p.answers.count() }}">
{{ votes / p.answers.count() }}% ({{ votes }})
</progress>
</td>
</tr>
{% endfor %}
</table>
{# Current user has already voted #}
{% elif p.has_voted(current_user) %}
<p><i>Vous avez déjà voté. Revenez plus tard pour voir les résultats</i></p>
{# Current user is a guest #}
{% elif not current_user.is_authenticated %}
<p><i>Seuls les membres peuvent voter</i></p>
{# Current user can vote #}
{% else %}
<form class="poll" action="" method="post" enctype="multipart/form-data">
<fieldset>
{% for choice in p.choices %}
<input type="{{ 'radio' if poll.type == 1 else 'checkbox' }}" id="{{ poll.id }}-{{ loop.index }}" name="pollanwsers" value="{{ choice }}" />
<label for="{{ poll.id }}-{{ loop.index }}">{{ choice }}</label><br>
{% endfor %}
</fieldset>
<input type="submit" value="Envoyer">
</form>
{% endif %}
</div>
{% endmacro %}