Пример #1
0
class Photo(db.Model):
    id = db.Column(db.Integer, primary_key=True)

    name = db.Column(db.String(64))
    picture = db.Column(db.String(128))
    md5 = db.Column(db.String(64))

    PICTURES_FOLDER = 'pictures/'

    @classmethod
    def create_from_file(cls, file, check_if_exists=True):
        # We check no photo with the same md5 already exists in db
        md5 = get_md5(file)
        if check_if_exists:
            photo = cls.query.filter_by(md5=md5).first()
            if photo is not None:
                return None

        # We copy the file
        _, filename = os.path.split(file)
        path = os.path.join('vktrainer', cls.PICTURES_FOLDER, md5)
        copyfile(file, path)

        name, _ = os.path.splitext(filename)
        photo = Photo(name=name, md5=md5, picture=path)
        db.session.add(photo)
        db.session.commit()
        return photo

    def get_path(self):
        return os.path.join(self.PICTURES_FOLDER, self.md5)

    def get_absolute_url(self):
        return url_for('vktrainer.show_photo', pk=self.id)
Пример #2
0
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)

    name = db.Column(db.String(64))

    def __repr__(self):
        return self.name

    @classmethod
    def get_or_create(cls, name):
        user = cls.query.filter(cls.name == name).first()

        if not user:
            user = cls(name=name)
            db.session.add(user)
            db.session.commit()

            return user, True

        return user, False
Пример #3
0
class TrainingPattern(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    training_set_id = db.Column(db.Integer, db.ForeignKey('training_set.id'))

    name = db.Column(db.String(64))
    instruction = db.Column(db.Text)
    training_set = db.relation('TrainingSet', backref=db.backref('patterns', lazy='dynamic'))
    pattern_ref = db.Column(db.String(64))
    position = db.Column(db.Integer)

    @property
    def pattern(self):
        from .patterns import REF_TO_PATTERN_CLASS
        try:
            return REF_TO_PATTERN_CLASS[self.pattern_ref]
        except KeyError:
            raise KeyError('Unknown pattern: {}'.format(self.pattern_ref))
Пример #4
0
class TrainingSet(db.Model):
    id = db.Column(db.Integer, primary_key=True)

    name = db.Column(db.String(64))
    photos = db.dynamic_loader(
        'Photo', secondary=photos, backref=db.backref('training_sets', lazy='dynamic'))

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return url_for('vktrainer.training_set', pk=self.id)

    def get_results_url(self):
        return url_for('vktrainer.training_set_results', pk=self.id)

    def get_leaderboard_url(self):
        return url_for('vktrainer.training_set_leaderboard', pk=self.id)

    def get_results(self):
        return [tr.get_pretty_result() for tr in self.training_results.all()]

    def get_leaderboard(self):
        count = func.count(TrainingResult.id)

        return self.training_results.join(
            TrainingResult.user,
        ).add_column(
            count,
        ).group_by(
            TrainingResult.user_id,
        ).order_by(
            desc(count),
        ).values(
            User.name,
            count,
        )

    def get_percentage_done(self):
        nb_photos_with_results = self.photos.filter(
            Photo.id.in_(self.training_results.with_entities(TrainingResult.photo_id))
        ).count()
        nb_photos = self.photos.count()

        return float(nb_photos_with_results) / nb_photos * 100

    def get_first_photo(self):
        if app.config['SHOW_PICTURES_ORDERING'] == 'linear':
            return self.photos.order_by('id').first()
        else:
            return self._get_next_photo_semi_random(None)

    def get_next_photo(self, photo):
        if app.config['SHOW_PICTURES_ORDERING'] == 'linear':
            return self._get_next_photo_linear(photo)
        else:
            return self._get_next_photo_semi_random(photo)

    def _get_next_photo_linear(self, photo):
        next_photo = self.photos.filter(Photo.id > photo.id).order_by('id').first()
        if not next_photo:
            # We are already at the last photo, we show the first one
            next_photo = self.photos.order_by('id').first()

        return next_photo

    def _get_previous_photo_linear(self, photo):
        previous_photo = self.photos.filter(Photo.id < photo.id).order_by('-id').first()
        if not previous_photo:
            # We are already at the first photo, we show the last one
            previous_photo = self.photos.order_by('-id').first()

        return previous_photo

    def _get_next_photo_semi_random(self, photo):
        """
        We serve a random photo without any results
        If there aren't any, we serve a random photo
        """

        photos_without_results = self.photos.filter(~Photo.id.in_(
            self.training_results.with_entities(TrainingResult.photo_id)
        ))
        if photo:
            photos_without_results = photos_without_results.filter(Photo.id != photo.id)

        nb_photos_without_results = photos_without_results.count()
        if nb_photos_without_results:
            return photos_without_results.all()[random.randint(0, nb_photos_without_results - 1)]
        else:
            nb_photos = self.photos.count()
            random_nb = random.randint(0, nb_photos - 1)
            return self.photos.all()[random_nb]

    def _get_previous_photo_semi_random(self, photo):
        # Don't want to allow previous photo in semi random mode (breaks UX)
        return None
Пример #5
0
class TrainingResult(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    training_set_id = db.Column(db.Integer, db.ForeignKey('training_set.id'))
    photo_id = db.Column(db.Integer, db.ForeignKey('photo.id'))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    training_set = db.relation('TrainingSet', backref=db.backref('training_results', lazy='dynamic'))
    photo = db.relation('Photo')
    user = db.relation('User', lazy='joined', backref=db.backref('training_results'))
    result = db.Column(db.Text)  # Result stored in JSON
    photo_is_incorrect = db.Column(db.Boolean, default=False)

    def get_absolute_url(self):
        return url_for(
            'vktrainer.training_set_result',
            training_set_pk=self.training_set.id,
            result_pk=self.id,
        )

    def get_pretty_result(self):
        if self.photo_is_incorrect:
            result = 'Photo marked as incorrect'
        else:
            try:
                loaded_result = json.loads(self.result)
            except ValueError:
                # Could not decode JSON
                loaded_result = None

            if loaded_result:
                result = {
                    'state': 'OK',
                    'value': loaded_result,
                }
            else:
                result = {
                    'state': 'KO',
                    'value': {},
                }

        return {
            'photo': {
                'name': self.photo.name,
                'id': self.photo.id,
            },
            'user': self.user.name if self.user else None,
            'result': result,
            'id': self.id,
            'url': self.get_absolute_url(),
        }

    @classmethod
    def create(cls, photo, training_set, user, result, **kwargs):
        training_result = cls(
            photo=photo,
            training_set=training_set,
            user=user,
            result=result,
            **kwargs
        )

        db.session.add(training_result)
        db.session.commit()

        return training_result
Пример #6
0
import os
import random
from shutil import copyfile

from flask import url_for, current_app as app
from flask_login import UserMixin

from sqlalchemy import func, desc

# from vktrainer import db, app, login_manager
from vktrainer import db, login_manager
from vktrainer.utils import get_md5


photos = db.Table('training_set_photos',
    db.Column('training_set_id', db.Integer, db.ForeignKey('training_set.id')),
    db.Column('photo_id', db.Integer, db.ForeignKey('photo.id'))
)


class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)

    name = db.Column(db.String(64))

    def __repr__(self):
        return self.name

    @classmethod
    def get_or_create(cls, name):
        user = cls.query.filter(cls.name == name).first()