Source code for fluxscoreboard.models.settings

# encoding: utf-8
from __future__ import unicode_literals, print_function, absolute_import
from fluxscoreboard.models import Base, DBSession
from fluxscoreboard.models.types import TZDateTime
from fluxscoreboard.util import is_admin_path
from pyramid.events import NewRequest, subscriber
from sqlalchemy.schema import Column
from sqlalchemy.types import Integer, Boolean, Unicode
import urlparse
import logging


log = logging.getLogger(__name__)


CTF_BEFORE = 1
CTF_STARTED = 2
CTF_ENDED = 3
CTF_ARCHIVE = 4


def load_settings(request):
    settings = DBSession.query(Settings).one()
    return settings


@subscriber(NewRequest)
def flash_global_announcement(event):
    session = event.request.session
    settings = event.request.settings
    url = urlparse.urlparse(event.request.url)
    # Flash only frontend and only once.
    if (not is_admin_path(event.request) and
            not url.path.startswith("/static") and
            settings.global_announcement):
        for msg in session.peek_flash('warning'):
            if msg == settings.global_announcement:
                break
        else:
            session.flash(settings.global_announcement, 'warning')


[docs]class Settings(Base): """ Represents application settings. Do **not** insert rows of this. There must always be only **one** row which is updated. This is preferred to having multiple rows with only key->value because with this we can enforce types and give an overview over available settings. The most straightforward usage is calling :func:`get` to retrieve the current settings which you can then also edit and they will be saved automatically. The following settings are available: ``submission_disabled``: A boolean that describes whether currently submissions are allowed or disabled. Default: ``False`` ``ctf_start_date``: A timezone-aware datetime value that describes when the CTF should start. Before that, the application will behave differently, e.g. may not allow login. ``ctf_end_date``: When the CTF will end. Same type as ``ctf_start_date``. ``ctf_started``: This is a property that can only be read and just compares ``ctf_start_date`` with the current time to find out whether the CTF has already started or not. ``archive_mode``: When the scoreboard is in archive mode, the frontend will not allow alteration to the database. Additionally, the whole system is public so everyone can get their solutions checked. This is then verified and the result is returned, but it is not added to the database. The following things will change in archive mode: - No registration - No login - Start / End times ignored - Solutions can be submitted but will only return the result, not enter something into the databse - Challenges are public in addition to the scoreboard ``ctf_state``: Which time state the CTF currently is in. Relevant for permissions etc. """ id = Column(Integer, primary_key=True) submission_disabled = Column(Boolean, default=False, nullable=False) ctf_start_date = Column(TZDateTime) ctf_end_date = Column(TZDateTime) archive_mode = Column(Boolean, default=False, nullable=False) playing_teams = Column(Integer, default=0, nullable=False) global_announcement = Column(Unicode) @property def ctf_started(self): from fluxscoreboard.util import now if self.ctf_start_date is None or self.ctf_end_date is None: return False now_ = now() return now_ >= self.ctf_start_date and now_ < self.ctf_end_date @property def ctf_ended(self): from fluxscoreboard.util import now if self.ctf_end_date is None: return False return now() >= self.ctf_end_date @property def ctf_state(self): if self.archive_mode: return CTF_ARCHIVE elif self.ctf_started: return CTF_STARTED elif self.ctf_ended: return CTF_ENDED else: return CTF_BEFORE