Commit 76b43f77 authored by Mindiell's avatar Mindiell

First commit

parents
__pycache__
config.py
This diff is collapsed.
# BrainBrain quizz
BrainBrain quizz is a web application
## Installation
Clone this repository
git clone --depth 1 https://framagit.org/brainbrain/bbquizz.git
[TODO]
Install is something like all those commands....
cd bbquizz
virtualenv -p python3 ve
source ve/bin/activate
pip install -r requirements.txt
cp config.py.sample config.py
vi config.py
export FLASK_APP=server.py
flask db upgrade
## Translation
See TRANSLATION.md
Supported languages are : English, French
## Testing
For testing, you should install more requirements :
pip install -r requirements-test.txt
And launch tests
nosetests
# Translation
use Flask-Babel for translations
## Extraction of strings to translate
pybabel extract -F app/babel.cfg -o messages.pot ./
## Initialisation of a specific language
pybabel init -i messages.pot -d translations -l fr
## Update of strings for all translated languages
pybabel update -i messages.pot -d translations
## Compile each languages to use them
pybabel compile -d translations
#encoding: utf-8
from flask_admin import Admin, expose, AdminIndexView
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from app.form.user import UserLoginForm
class IndexView(AdminIndexView):
@expose('/')
def index(self):
form = UserLoginForm()
return self.render('admin/index.html', form=form)
admin = Admin(index_view=IndexView())
api = Api()
db = SQLAlchemy()
migrate = Migrate()
[python: **.py]
[jinja2: **/view/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_
#encoding: utf-8
from flask import g, redirect, url_for, flash, session
from flask_babel import gettext as _
from flask_login import login_user, logout_user
from flask_admin import BaseView, expose
from app import admin
from app.controller.controller import Controller
from app.form.user import UserLoginForm
from app.model.user import User
class Admin(Controller):
def login(self):
g.form = UserLoginForm()
if g.form.validate_on_submit():
user = User.query.filter_by(
login=g.form.login.data,
password=g.form.password.data
).first()
if user:
if user.is_active:
login_user(user)
return redirect(url_for("admin.index"))
else:
flash(_("Account not active."), "warning")
for (field, message) in g.form.errors.items():
flash("%s: %s" % (field, message[0]))
return redirect(url_for('admin.index'))
class LogoutView(BaseView):
@expose('/')
def index(self):
logout_user()
session.clear()
return redirect(url_for('admin.index'))
#TODO: Display this link in Admin menu only if user is authenticated
admin.add_view(LogoutView(name='Logout', endpoint='logout'))
#encoding: utf-8
from flask import render_template, g, session, flash, redirect, url_for
import json
from app.controller.controller import Controller
from app.form.game import GamePlayForm
from app.model.game import Game as GameModel
from app.model.player import Player as PlayerModel
from app.model.result import Result as ResultModel
class UserApi(Controller):
def game(self, game_id):
game = GameModel.query.get(game_id)
if game is None:
return json.dumps({})
players = [{
"id": player.id,
"pseudo": player.pseudo,
"score": 0,
} for player in game.players.all()]
for player in players:
results = ResultModel.query.filter_by(game_id=game.id,player_id=player["id"]).all()
if len(results)>0:
player["score"] = sum([result.score for result in results if result.score is not None])
answered = 0;
if game.question>0:
answered = ResultModel.query.filter_by(question=game.question, game_id=game.id).count()
return json.dumps({
"status" : game.status,
"question": game.question,
"players": players,
"connected": sum([1 for player in game.players.all() if player.status=="connected"]),
"answered": answered,
})
def connect(self, player_id):
player = PlayerModel.query.get(player_id)
player.status = "connected"
player.save()
return json.dumps({
"game_id" : player.game.id,
})
def answer(self, player_id, answer_id):
player = PlayerModel.query.get(player_id)
score = 0
if int(player.game.quizz.questions.all()[player.game.question-1].answer)==int(answer_id):
score = 1
result = ResultModel(
question = player.game.question,
answer = answer_id,
time = 0,
score = score,
game_id = player.game.id,
player_id = player.id,
)
result.save()
return json.dumps([])
class MasterApi(Controller):
def game(self, game_id):
game = GameModel.query.get(game_id)
return json.dumps({
"players": [player.pseudo for player in game.players.all()],
"connected": sum([1 for player in game.players.all() if player.status=="connected"]),
})
def answers(self, game_id):
game = GameModel.query.get(game_id)
game.status = "answers"
game.save()
return json.dumps([])
def scores(self, game_id):
game = GameModel.query.get(game_id)
game.status = "scores"
game.save()
return json.dumps([])
#encoding: utf-8
class Controller():
@classmethod
def as_view(cls, function_name, *class_args, **class_kwargs):
# Create the view function to return
def view(*args, **kwargs):
self = view.view_class(*class_args, **class_kwargs)
if hasattr(self, function_name):
return getattr(self, function_name)(*args, **kwargs)
else:
return "Class %s has no method called %s" % (cls.__name__, function_name)
view.view_class = cls
# name used for endpoint : Class name + function name
view.__name__ = '.'.join((cls.__name__.lower(), function_name))
view.__doc__ = cls.__doc__
view.__module__ = cls.__module__
return view
#encoding: utf-8
from flask import render_template
from app.controller.controller import Controller
class Core(Controller):
def home(self):
return render_template('core/home.html')
#encoding: utf-8
from flask import render_template, g, session, flash, redirect, url_for
import random
from app.controller.controller import Controller
from app.form.game import GamePlayForm
from app.model.quizz import Quizz as QuizzModel
from app.model.game import Game as GameModel
from app.model.player import Player as PlayerModel
from app.model.result import Result as ResultModel
class Game(Controller):
def create(self, quizz_id):
"""
Select one quizz to start a new game
"""
gin = "".join([str(random.randint(0,9)) for i in range(0,6)])
while GameModel.query.filter_by(gin=gin).count()>0:
gin = "".join([str(random.randint(0,9)) for i in range(0,6)])
g.game = GameModel(quizz_id=quizz_id, status="waiting")
g.game.gin = gin
g.game.save()
session["game_id"] = g.game.id
return redirect(url_for("game.waiting"))
def waiting(self):
"""
Waiting for participants to connect
"""
g.game = GameModel.query.get(session["game_id"])
if g.game is None:
return redirect(url_for("quizz.list"))
return render_template("game/waiting.html")
def start(self):
"""
Starting game, waiting for participants being ready
"""
g.game = GameModel.query.get(session["game_id"])
if g.game is None:
return redirect(url_for("quizz.list"))
g.game.status = "starting"
g.game.gin = ""
g.game.save()
return render_template("game/starting.html")
def question(self):
"""
Playing next question
"""
g.game = GameModel.query.get(session["game_id"])
if g.game is None:
return redirect(url_for("quizz.list"))
if g.game.question + 1>len(g.game.quizz.questions.all()):
g.game.status = "resume"
g.game.save()
return redirect(url_for("game.resume"))
g.game.status = "started"
g.game.question = g.game.question + 1
g.game.save()
g.question = g.game.quizz.questions.all()[g.game.question-1]
return render_template("game/question.html")
def resume(self):
g.game = GameModel.query.get(session["game_id"])
if g.game is None:
return redirect(url_for("quizz.list"))
return render_template("game/resume.html")
#encoding: utf-8
from flask import render_template, g, session, flash, redirect, url_for
from flask_babel import gettext as _
import random
from app.controller.controller import Controller
from app.form.game import GamePlayForm
from app.model.game import Game as GameModel
from app.model.player import Player as PlayerModel
from app.model.result import Result as ResultModel
class Player(Controller):
def play(self):
"""
Try to connect to an existing game
"""
g.form = GamePlayForm()
if g.form.validate_on_submit():
# Is this game exists ?
game = GameModel.query.filter_by(gin=g.form.gin.data).first()
if game is None:
flash(_("This game does not exists, please try again"), "error")
return redirect(url_for("player.play"))
# Is a player already exists with the same pseudo ?
player = PlayerModel.query.filter_by(game_id=game.id, pseudo=g.form.pseudo.data).first()
if player is not None:
flash(_("This pseudo already exists, please choose another one"), "error")
return redirect(url_for("player.play"))
else:
# Ok, We attach new player to this game
player = PlayerModel(game_id=game.id, pseudo=g.form.pseudo.data)
player.save()
session["player_id"] = player.id
return redirect(url_for('player.waiting'))
return render_template('player/play.html')
def waiting(self):
g.player = PlayerModel.query.get(session["player_id"])
if g.player is None:
return redirect(url_for('player.play'))
return render_template("player/waiting.html")
def connecting(self):
g.player = PlayerModel.query.get(session["player_id"])
if g.player is None:
return redirect(url_for('player.play'))
return render_template("player/connecting.html")
def playing(self):
g.player = PlayerModel.query.get(session["player_id"])
if g.player is None:
return redirect(url_for('player.play'))
return render_template("player/playing.html")
def resume(self):
g.player = PlayerModel.query.get(session["player_id"])
if g.player is None:
return redirect(url_for('player.play'))
return render_template("player/resume.html")
#encoding: utf-8
from flask import render_template, g, session, flash, redirect, url_for
from flask_babel import gettext as _
import random
from app.controller.controller import Controller
from app.form.quizz import QuizzCreateForm, QuestionCreateForm
from app.model.quizz import Quizz as QuizzModel
from app.model.question import Question as QuestionModel
class Quizz(Controller):
def create(self):
g.form = QuizzCreateForm()
if g.form.validate_on_submit():
quizz = QuizzModel(
name = g.form.name.data
)
quizz.save()
session["quizz_id"] = quizz.id
flash(_("Quizz created"), "success")
return redirect(url_for("quizz.add_question"))
return render_template("quizz/create.html")
def add_question(self):
g.form = QuestionCreateForm()
g.quizz = QuizzModel.query.get(session["quizz_id"])
if g.form.validate_on_submit():
question = QuestionModel(
quizz_id = g.quizz.id,
question = g.form.question.data,
answer_1 = g.form.answer_1.data,
answer_2 = g.form.answer_2.data,
answer_3 = g.form.answer_3.data,
answer_4 = g.form.answer_4.data,
answer = g.form.answer.data
)
question.save()
flash(_("Question created"), "success")
return redirect(url_for("quizz.add_question"))
return render_template("quizz/add_question.html")
def list(self):
"""
List quizzes
"""
g.quizzes = QuizzModel.query.all()
return render_template("quizz/list.html")
#encoding: utf-8
from flask import render_template, g, url_for, redirect, flash, session
from flask_babel import gettext as _
from flask_login import login_user, logout_user
from app.controller.controller import Controller
from app.form.user import UserLoginForm
from app.model.user import User as UserModel
class User(Controller):
def login(self):
g.form = UserLoginForm()
if g.form.validate_on_submit():
user = UserModel.query.filter_by(
login=g.form.login.data,
password=g.form.password.data
).first()
if user:
if user.is_active:
login_user(user)
return redirect(url_for("core.home"))
else:
flash(_("Account not active."), "warning")
for (field, message) in g.form.errors.items():
flash("%s: %s" % (field, message[0]))
return render_template("user/login.html")
def logout(self):
logout_user()
session.clear()
return redirect(url_for("core.home"))
#encoding: utf-8
from flask_wtf import FlaskForm
from flask_babel import gettext as _
from wtforms import StringField
from wtforms.validators import DataRequired
class GamePlayForm(FlaskForm):
gin = StringField(_("Game Identification Number"), validators=[DataRequired()])
pseudo = StringField(_("Pseudo to use"), validators=[DataRequired()])
#encoding: utf-8
from flask_wtf import FlaskForm
from flask_babel import gettext as _
from wtforms import StringField, SelectField
from wtforms.validators import DataRequired
class QuizzCreateForm(FlaskForm):
name = StringField(_("Name"), validators=[DataRequired()])
class QuestionCreateForm(FlaskForm):
question = StringField(_("Question"), validators=[DataRequired()])
answer_1 = StringField(_("Answer 1"), validators=[DataRequired()])
answer_2 = StringField(_("Answer 2"))
answer_3 = StringField(_("Answer 3"))
answer_4 = StringField(_("Answer 4"))
answer = SelectField(_("Correct answer"), coerce=int, choices=(
(1, _("Answer 1")),
(2, _("Answer 2")),
(3, _("Answer 3")),
(4, _("Answer 4")),
),
validators=[DataRequired()]
)
#encoding: utf-8
from flask_wtf import FlaskForm
from flask_babel import gettext as _
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired
class UserLoginForm(FlaskForm):
login = StringField(_("Login"), validators=[DataRequired()])
password = PasswordField(_("Password"), validators=[DataRequired()])
#encoding: utf-8
import app.model.user
import app.model.quizz
import app.model.question
import app.model.game
import app.model.player
import app.model.result
#encoding: utf-8
from app import admin, db
from app.model.model import Model, View
class Game(db.Model, Model):
id = db.Column(db.Integer, primary_key=True)
quizz_id = db.Column(db.Integer, db.ForeignKey('quizz.id'))
quizz = db.relationship('Quizz', backref=db.backref('games', lazy='dynamic'))
gin = db.Column(db.String(6))
question = db.Column(db.Integer, default=0)
status = db.Column(db.String(30))
def __repr__(self):
return "%s" % self.gin
# Model will be automatically managed through flask-admin module
admin.add_view(View(Game, db.session))
#encoding: utf-8
from flask import redirect, request, url_for
from flask_admin.contrib.sqla import ModelView
from flask_login import current_user
from app import db
class View(ModelView):
def is_accessible(self):
if not current_user.is_authenticated:
return False
return current_user.is_authenticated and current_user.admin
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for('admin.login', next=request.url))
class Model():
def save(self):
is_existing = True
if len(self.__table__.primary_key.columns.keys())>1:
is_existing = False
else:
for column_name in self.__table__.primary_key.columns.keys():
column = self.__getattribute__(column_name)
if column is None or column=='':
is_existing = False
if not is_existing:
db.session.add(self)
db.session.commit()
def delete(self):
is_existing = True
for column_name in self.__table__.primary_key.columns.keys():
column = self.__getattribute__(column_name)
if column is None or column=='':
is_existing = False
if is_existing:
db.session.delete(self)
db.session.commit()
#encoding: utf-8
from app import admin, db
from app.model.model import Model, View
class Player(db.Model, Model):
id = db.Column(db.Integer, primary_key=True)
pseudo = db.Column(db.String(30))
game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
game = db.relationship('Game', backref=db.backref('players', lazy='dynamic'))
status = db.Column(db.String(30))
def __repr__(self):
return "%s" % self.pseudo
# Model will be automatically managed through flask-admin module
admin.add_view(View(Player, db.session))
#encoding: utf-8
from app import admin, db
from app.model.model import Model, View
class Question(db.Model, Model):
id = db.Column(db.Integer, primary_key=True)
quizz_id = db.Column(db.Integer, db.ForeignKey('quizz.id'))
quizz = db.relationship('Quizz', backref=db.backref('questions', lazy='dynamic'))
question = db.Column(db.String(300))
answer_1 = db.Column(db.String(300))
answer_2 = db.Column(db.String(300))
answer_3 = db.Column(db.String(300))
answer_4 = db.Column(db.String(300))
answer = db.Column(db.Integer)
def __repr__(self):
return "%s" % self.question
# Model will be automatically managed through flask-admin module
admin.add_view(View(Question, db.session))
#encoding: utf-8
from app import admin, db
from app.model.model import Model, View
class Quizz(db.Model, Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(300))
def __repr__(self):
return "%s" % self.name
# Model will be automatically managed through flask-admin module
admin.add_view(View(Quizz, db.session))
#encoding: utf-8
from app import admin, db
from app.model.model import Model, View
class Result(db.Model, Model):
id = db.Column(db.Integer, primary_key=True)
question = db.Column(db.Integer)
answer = db.Column(db.Integer)
time = db.Column(db.Integer)
score = db.Column(db.Integer, default=0)
game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
game = db.relationship('Game', backref=db.backref('results', lazy='dynamic'))
player_id = db.Column(db.Integer, db.ForeignKey('player.id'))
player = db.relationship('Player', backref=db.backref('results', lazy='dynamic'))
def __repr__(self):
return "%s" % self.question
# Model will be automatically managed through flask-admin module
admin.add_view(View(Result, db.session))
#encoding: utf-8
from app import admin, db
from app.model.model import Model, View
def get_user(user_id):
return User.query.get(user_id)
class User(db.Model, Model):
id = db.Column(db.Integer, primary_key=True)
login = db.Column(db.String(1000))
password = db.Column(db.String(64))
email = db.Column(db.String(1000))
active = db.Column(db.Boolean)
admin = db.Column(db.Boolean)
@property
def is_authenticated(self):
return self.id is not None
@property
def is_active(self):
return self.active or False