Beispiel #1
0
class GameScreenshot(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(255))
    caption = db.Column(db.Text)
    index = db.Column(db.Integer)  # 0..n-1
    game_id = db.Column(db.Integer, db.ForeignKey("game.id"))

    def __init__(self, url, caption, game):
        self.game = game
        self.url = url
        self.caption = caption
        self.index = len(self.game.screenshots) - 1

    def __repr__(self):
        return "<GameScreenshot %r>" % self.id

    def move(self, x):
        all = self.game.screenshotsOrdered

        old = self.index
        new = self.index + x

        if new >= len(all):
            new = len(all) - 1
        if new < 0:
            new = 0

        if new != self.index:
            other = all[new]
            self.index = new
            other.index = old
Beispiel #2
0
class EntryPackage(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(256))
    entry_id = db.Column(db.Integer, db.ForeignKey("entry.id"))
    type = db.Column(
        db.Enum(
            "web",  # Flash, html5, js...
            "linux",  # Linux binaries (e.g. *.tar.gz)
            "linux32",  # Linux32 binaries (e.g. *.tar.gz)
            "linux64",  # Linux64 binaries (e.g. *.tar.gz)
            "windows",  # Windows binaries (e.g. *.zip, *.exe)
            "windows64",  # Windows64 binaries (e.g. *.zip, *.exe)
            "mac",  # MacOS application packages
            "combi",  # Linux + Windows + Source (and more, optional)
            "love",  # Löve packages
            "blender",  # Blender save file (*.blend)
            "source",  # Source package (e.g. *.zip or *.tar.gz)
            "git",  # Version control repository: GIT
            "svn",  # Version control repository: SVN
            "hg",  # Version control repository: HG
            "unknown"))

    def __init__(self, entry, url, type="unknown"):
        self.url = url
        self.type = type
        self.entry = entry

    def __repr__(self):
        return "<EntryPackage %r>" % self.id

    def typeString(self):
        return entry_package_type_string(self.type)
Beispiel #3
0
class JamPhoto(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    jam_id = db.Column(db.Integer, db.ForeignKey('jam.id'))
    photo = db.Column(LONGBLOB)

    def __init__(self, jam_id, photo):
        self.jam_id = jam_id
        self.photo = photo
Beispiel #4
0
class Announcement(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.Text)
    posted = db.Column(db.DateTime)

    def __init__(self, text):
        self.text = text
        self.posted = datetime.utcnow()

    def __repr__(self):
        return '<Announcement %r>' % self.id
Beispiel #5
0
class EntryScreenshot(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(256))
    caption = db.Column(db.Text)
    entry_id = db.Column(db.Integer, db.ForeignKey("entry.id"))

    def __init__(self, url, caption, entry):
        self.entry = entry
        self.url = url
        self.caption = caption

    def __repr__(self):
        return "<EntryScreenshot %r>" % self.id
Beispiel #6
0
class RatingSkip(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    reason = db.Column(db.Enum("platform", "uninteresting", "crash"))
    entry_id = db.Column(db.Integer, db.ForeignKey("entry.id"))
    participant_id = db.Column(db.Integer, db.ForeignKey("participant.id"))

    def __init__(self, participant, entry, reason):
        self.participant = participant
        self.entry = entry
        self.reason = reason

    def __repr__(self):
        return "<RatingSkip %r>" % self.id
Beispiel #7
0
class Comment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.Text)
    posted = db.Column(db.DateTime)
    entry_id = db.Column(db.Integer, db.ForeignKey('entry.id'))
    participant_id = db.Column(db.Integer, db.ForeignKey('participant.id'))

    def __init__(self, text, entry, participant):
        self.text = text
        self.entry = entry
        self.participant = participant
        self.posted = datetime.utcnow()

    def __repr__(self):
        return '<Comment %r>' % self.id
Beispiel #8
0
class Comment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.Text)
    posted = db.Column(db.DateTime)
    game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __init__(self, text, game, user):
        self.text = text
        self.game = game
        self.user = user
        self.posted = datetime.utcnow()

    def __repr__(self):
        return f'<Comment {self.id}>'
Beispiel #9
0
class Vote(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
    jam_id = db.Column(db.Integer, db.ForeignKey('jam.id'))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    voted_at = db.Column(db.DateTime)

    def __init__(self, game, user):
        self.game = game
        self.jam = game.jam
        self.user = user
        self.voted_at = datetime.utcnow()

        self.game_id = game.id
        self.jam_id = game.jam_id
        self.user_id = user.id
Beispiel #10
0
class Rating(db.Model):
    """The rating of a category is set to 0 to disable this category. It is
    then not counted into the average score.
    """

    id = db.Column(db.Integer, primary_key=True)
    score = db.Column(db.SmallInteger)
    text = db.Column(db.Text)
    posted = db.Column(db.DateTime)
    game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __init__(self, game, user, text, score):
        self.game = game
        self.user = user
        self.text = text
        self.posted = datetime.utcnow()
        self.score = score

    def __repr__(self):
        return f"<Rating {self.id}:{self.score}>"

    def set(self, category, value):
        if category in (None, "overall"):
            self.score = value
        else:
            setattr(self, "score_" + category, value)

    def get(self, category):
        return self.score if category in (None, "overall") else getattr(
            self, "score_" + category)
Beispiel #11
0
class Invitation(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    team_id = db.Column(db.Integer, db.ForeignKey("team.id"))
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"))

    def __init__(self, team, user):
        self.team = team
        self.user = user

    def url(self, **values):
        return url_for("invitation", id=self.id, _external=True, **values)

    def canAccept(self):
        return self.team.jam.getStatus().code <= JamStatusCode.PACKAGING

    def accept(self):
        self.team.userJoin(self.user)
        db.session.delete(self)
        db.session.commit()

    def decline(self):
        db.session.delete(self)
        db.session.commit()
Beispiel #12
0
class Participation(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    team_id = db.Column(db.Integer, db.ForeignKey("team.id"))
    jam_id = db.Column(db.Integer, db.ForeignKey("jam.id"))
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
    show_in_finder = db.Column(db.Boolean, default = True)
    registered = db.Column(db.DateTime)

    def __init__(self, user, jam, show_in_finder = True):
        self.user = user
        self.jam = jam
        self.show_in_finder = show_in_finder
        self.registered = datetime.utcnow()
Beispiel #13
0
class Rating(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    score_gameplay = db.Column(db.SmallInteger)
    score_graphics = db.Column(db.SmallInteger)
    score_audio = db.Column(db.SmallInteger)
    score_innovation = db.Column(db.SmallInteger)
    score_story = db.Column(db.SmallInteger)
    score_technical = db.Column(db.SmallInteger)
    score_controls = db.Column(db.SmallInteger)
    score_overall = db.Column(db.SmallInteger)
    text = db.Column(db.Text)
    posted = db.Column(db.DateTime)
    entry_id = db.Column(db.Integer, db.ForeignKey('entry.id'))
    participant_id = db.Column(db.Integer, db.ForeignKey('participant.id'))

    def __init__(self, score_gameplay, score_graphics, score_audio,
                 score_innovation, score_story, score_technical,
                 score_controls, score_overall, text, entry, participant):
        self.score_gameplay = score_gameplay
        self.score_graphics = score_graphics
        self.score_audio = score_audio
        self.score_innovation = score_innovation
        self.score_story = score_story
        self.score_technical = score_technical
        self.score_controls = score_controls
        self.score_overall = score_overall
        self.text = text
        self.entry = entry
        self.participant = participant
        self.posted = datetime.utcnow()

    def __repr__(self):
        return '<Rating %r>' % self.id

    def getAverage(self):
        return (self.score_gameplay + self.score_graphics + self.score_audio +
                self.score_innovation + self.score_story + self.score_technical
                + self.score_controls + self.score_overall) * 1.0 / 8.0
Beispiel #14
0
    score = db.Column(db.SmallInteger)
    text = db.Column(db.Text)
    posted = db.Column(db.DateTime)
    game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __init__(self, game, user, text, score):
        self.game = game
        self.user = user
        self.text = text
        self.posted = datetime.utcnow()
        self.score = score

    def __repr__(self):
        return f"<Rating {self.id}:{self.score}>"

    def set(self, category, value):
        if category in (None, "overall"):
            self.score = value
        else:
            setattr(self, "score_" + category, value)

    def get(self, category):
        return self.score if category in (None, "overall") else getattr(
            self, "score_" + category)


# Add fields "dynamically"
for c in RATING_CATEGORIES:
    setattr(Rating, f"score_{c}", db.Column(db.SmallInteger, default=5))
Beispiel #15
0
class Team(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    jam_id = db.Column(db.Integer, db.ForeignKey("jam.id"))
    name = db.Column(db.String(80))

    description = db.Column(db.Text)
    livestreams = db.Column(db.Text)  # list of livestreams, one URL per file
    irc = db.Column(db.String(128))

    participations = db.relationship("Participation",
                                     backref="team",
                                     lazy="subquery")
    invitations = db.relationship("Invitation",
                                  backref="team",
                                  lazy="subquery")
    games = db.relationship("Game", backref="team", lazy="subquery")

    def __init__(self, user, jam):
        self.jam = jam
        self.user_join(user)
        self.name = user.username + "'s team"

    @property
    def members(self):
        return [r.user for r in self.participations]

    @property
    def game(self):
        return self.games[0] if self.games else None

    @property
    def is_single_team(self):
        return len(self.participations) == 1

    def url(self, **kwargs):
        return url_for("jam_team",
                       jam_slug=self.jam.slug,
                       team_id=self.id,
                       **kwargs)

    def user_join(self, user):
        r = user.get_participation(self.jam)
        if not r:
            # register user, but do not create automatic team, we don't need
            # that anyway
            user.join_jam(self.jam, False)
        elif r in self.participations:
            return  # user is already in this team
        elif r.team and r.team != self:
            r.team.user_leave(user)

        r.team = self
        db.session.commit()

    def user_leave(self, user):
        r = user.get_participation(self.jam)

        if r.team != self:
            return  # not in this team, nevermind ;)

        if self.is_single_team:
            # only user in team, we can destroy this team
            self.destroy()

        r.team = None
        db.session.commit()

    def destroy(self):
        # also destroy all the games, invitations
        for game in self.games:
            game.destroy()
        for invitation in self.invitations:
            db.session.delete(invitation)
        db.session.delete(self)

    @property
    def number_members_and_invitations(self):
        return len(self.members) + len(self.invitations)

    def can_invite(self, user):
        return user in self.members and (
            self.jam.team_limit == 0
            or self.jam.team_limit > self.number_members_and_invitations)

    def get_invitation(self, user):
        return Invitation.query.filter_by(user_id=user.id,
                                          team_id=self.id).first()

    def invite_user(self, user,
                    sender):  # sender: which user sent the invitation
        if not user.notify_team_invitation:
            return None

        if self.get_invitation(user):
            i = self.get_invitation(user)  # already invited
        else:
            i = Invitation(self, user)
            db.session.add(i)
            db.session.commit()
            body = render_template("emails/invitation.txt",
                                   team=self,
                                   sender=sender,
                                   recipient=user,
                                   invitation=i)
            mail.send_message(subject=app.config["LONG_NAME"] +
                              ": You have been invited to " + self.name,
                              recipients=[user.email],
                              body=body)
        return i
Beispiel #16
0
    def feedbackAverage(self, category):
        if category in (None, "overall"):
            return self.score
        return average_non_zero([r.get(category) for r in self.ratings])

    @property
    def rank(self):
        jam_games = list(self.jam.games.all())
        jam_games.sort(key="score", reverse=True)
        return jam_games.index(self) + 1

    @property
    def numberRatings(self):
        return len(self.ratings)

    @property
    def ratingCategories(self):
        return [
            c for c in RATING_CATEGORIES
            if getattr(self, "score_" + c + "_enabled")
        ]

    def getRatingByUser(self, user):
        return Rating.query.filter_by(user_id=user.id).first()


# Adds fields "dynamically" (which score categories are enabled?)
for c in RATING_CATEGORIES:
    setattr(Game, "score_" + c + "_enabled", db.Column(db.Boolean,
                                                       default=True))
Beispiel #17
0
    # score_CATEGORY = db.Column(db.SmallInteger, default = 5)
    text = db.Column(db.Text)
    posted = db.Column(db.DateTime)
    game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __init__(self, game, user, text, score):
        self.game = game
        self.user = user
        self.text = text
        self.posted = datetime.utcnow()
        self.score = score

    def __repr__(self):
        return '<Rating %r:%r>' % (self.id, self.score)

    def set(self, category, value):
        if category in (None, "overall"):
            self.score = value
        else:
            setattr(self, "score_" + category, value)

    def get(self, category):
        return self.score if category in (None, "overall") else getattr(
            self, "score_" + category)


# Add fields "dynamically"
for c in RATING_CATEGORIES:
    setattr(Rating, "score_" + c, db.Column(db.SmallInteger, default=5))
Beispiel #18
0
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    password = db.Column(db.LargeBinary())
    token = db.Column(db.BigInteger, nullable=True, default=None)
    email = db.Column(db.String(191), unique=True)
    new_email = db.Column(db.String(191), unique=True)
    is_admin = db.Column(db.Boolean, default=False)
    is_verified = db.Column(db.Boolean)
    is_deleted = db.Column(db.Boolean, default=False)
    registered = db.Column(db.DateTime)
    ratings = db.relationship('Rating', backref='user', lazy="dynamic")
    comments = db.relationship('Comment', backref='user', lazy="dynamic")
    invitations = db.relationship("Invitation", backref="user", lazy="dynamic")
    participations = db.relationship("Participation", backref=db.backref("user", lazy="joined"), lazy="subquery")

    ability_programmer = db.Column(db.Boolean)
    ability_gamedesigner = db.Column(db.Boolean)
    ability_2dartist = db.Column(db.Boolean)
    ability_3dartist = db.Column(db.Boolean)
    ability_composer = db.Column(db.Boolean)
    ability_sounddesigner = db.Column(db.Boolean)
    abilities_extra = db.Column(db.String(128))
    location = db.Column(db.String(128))
    location_coords = db.Column(db.String(128))
    location_display = db.Column(db.String(128))
    location_flag = db.Column(db.String(16), default="unknown")
    real_name = db.Column(db.String(128))
    about = db.Column(db.Text)
    website = db.Column(db.String(128))
    avatar = db.Column(db.String(128))

    pm_mode = db.Column(db.Enum("email", "form", "disabled"), default="form")

    notify_new_jam = db.Column(db.Boolean, default=True)
    notify_jam_start = db.Column(db.Boolean, default=True)
    notify_jam_finish = db.Column(db.Boolean, default=True)
    notify_game_comment = db.Column(db.Boolean, default=True)
    notify_team_invitation = db.Column(db.Boolean, default=True)
    notify_newsletter = db.Column(db.Boolean, default=True)

    def __init__(self, username, password, email, is_admin=False, is_verified=False):
        self.username = username
        self.password = hash_password(password)
        self.email = email
        self.new_email = email
        self.is_admin = is_admin
        self.is_verified = is_verified
        self.registered = datetime.utcnow()

    @property
    def is_active(self):
        return self.is_verified

    @property
    def is_anonymous(self):
        return False

    @property
    def is_authenticated(self):
        return True

    def __repr__(self):
        return '<User %r>' % self.username

    def get_id(self):
        return self.id

    def getVerificationHash(self):
        # combine a few properties, hash it
        # take first 16 chars for simplicity
        # make it email specific
        hash = scrypt.hash(str(self.username) + str(self.new_email), app.config['SECRET_KEY'])
        return hash.encode('hex')[:16]

    def getResetToken(self):
        # combine a few properties, hash it
        # take first 16 chars for simplicity
        hash = scrypt.hash(str(self.token), app.config['SECRET_KEY'])
        return hash.encode('hex')[:16]

    def ratedGame(self, game):
        return self.ratings.filter_by(game=game).first() != None

    def getRatingCount(self, jam):
        i = 0
        for r in self.ratings:
            if r.game.jam == jam:
                i += 1
        return i

    @property
    def games(self):
        g = []
        for p in self.participations:
            if p.team:
                for game in p.team.games:
                    if not game.is_deleted:
                        g.append(game)

        import operator
        g.sort(key=operator.attrgetter("created"))

        return g

    def url(self, **values):
        return url_for('show_user', username=self.username, **values)

    def getAvatar(self, size=32):
        if self.avatar:
            return self.avatar.replace("%s", str(size))
        return "//gravatar.com/avatar/{0}?s={1}&d=identicon".format(md5(self.email.lower()).hexdigest(), size)

    def setLocation(self, location):
        if not location:
            self.location = ""
            self.location_display = ""
            self.location_coords = ""
            self.location_flag = "unknown"
            return True

        new_loc, new_coords, new_flag = findLocation(location)
        if not new_loc:
            return False
        self.location = location
        self.location_display = new_loc
        self.location_coords = new_coords
        self.location_flag = new_flag
        return True

    def getLocation(self):
        return Markup('<span class="location"><span class="flag %s"></span> <span class="city">%s</span></span>' % (self.location_flag, self.location_display or "n/a"))

    def getLink(self, class_ = "", real = True, avatar = True):
        if self.is_deleted:
            return Markup('<span class="user deleted">[DELETED]</span>')

        s = 16
        if self.is_admin:
            class_ += " admin"

        link = ''
        link += '<a class="user {0}" href="{1}">'.format(class_, self.url())
        if avatar:
            link += '<img width="{0}" height="{0}" src="{1}" class="icon"/> '.format(s, self.getAvatar(s))
        link += '<span class="name"><span class="username">{0}</span>'.format(self.username)
        link += u' <span class="real">({0})</span>'.format(self.real_name) if self.real_name and real else ''
        link += '</span></a>'

        return Markup(link)

    @property
    def abilities(self):
        a = []
        if self.ability_programmer:
            a.append("Programming")
        if self.ability_gamedesigner:
            a.append("Game Design")
        if self.ability_2dartist:
            a.append("Graphics / 2D Art")
        if self.ability_3dartist:
            a.append("Modelling / 3D Art")
        if self.ability_composer:
            a.append("Composing")
        if self.ability_sounddesigner:
            a.append("Sound Design")
        return a

    def abilityString(self):
        a = ", ".join(self.abilities)
        if self.abilities_extra:
            a += '<div class="ability-extra">' + self.abilities_extra + '</div>'
        return a

    def getParticipation(self, jam):
        return Participation.query.filter_by(user_id = self.id, jam_id = jam.id).first()

    def getTeam(self, jam):
        p = self.getParticipation(jam)
        return p.team if p and p.team else None

    def inTeam(self, team):
        return self in team.members

    def canRate(self, game):
        return not self.inTeam(game.team)

    def canEdit(self, game):
        return self.inTeam(game.team)

    def joinJam(self, jam, generateTeam = True):
        p = Participation(self, jam)
        db.session.add(p)
        db.session.commit() # need to commit so the team does not register us automatically

        if generateTeam:
            self.generateTeam(jam)
        else:
            db.session.commit()

    def generateTeam(self, jam):
        t = Team(self, jam)
        db.session.add(t)
        db.session.commit()

    def leaveJam(self, jam):
        # leave team
        if self.getTeam(jam):
            self.getTeam(jam).userLeave(self) #  will destroy the team if then empty

        # delete registration
        if self.getParticipation(jam):
            db.session.delete(self.getParticipation(jam))

    def numberOfGames(self):
        return len(self.games)

    @property
    def openInvitations(self):
        invitations = []
        for invitation in self.invitations:
            if invitation.canAccept():
                invitations.append(invitation)
        return invitations
class GamescomApplication(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    year = db.Column(db.Integer)
    title = db.Column(db.String(128))
    city = db.Column(db.String(128))
    country = db.Column(db.String(128))
    zip_code = db.Column(db.String(128))
    street = db.Column(db.String(128))
    job_title = db.Column(db.String(128))
    experience = db.Column(db.String(128))
    reason = db.Column(db.String(255))
    travel_funding_amount = db.Column(db.Integer)
    travel_funding_reason = db.Column(db.String(255))

    def __init__(self, user):
        self.user = user
        self.user_id = user.id
Beispiel #20
0
class Game(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(128))
    slug = db.Column(db.String(128))
    created = db.Column(db.DateTime)
    description = db.Column(db.Text)
    technology = db.Column(db.Text)
    help = db.Column(db.Text)
    is_deleted = db.Column(db.Boolean, default=False)
    has_cheated = db.Column(db.Boolean, default=False)

    jam_id = db.Column(db.Integer, db.ForeignKey('jam.id'))
    team_id = db.Column(db.Integer, db.ForeignKey('team.id'))
    ratings = db.relationship('Rating', backref='game', lazy="subquery")
    comments = db.relationship('Comment', backref='game', lazy="subquery")
    packages = db.relationship('GamePackage', backref='game', lazy="subquery")
    screenshots = db.relationship('GameScreenshot',
                                  backref='game',
                                  lazy="subquery")

    def __init__(self, team, title):
        self.team = team
        self.jam = team.jam
        self.title = title
        self.slug = get_slug(title)
        self.created = datetime.utcnow()

    def __repr__(self):
        return f"<Game {self.title}>"

    def destroy(self):
        # destroy all ratings, comments, packages, screenshots
        for rating in self.ratings:
            db.session.delete(rating)
        for comment in self.comments:
            db.session.delete(comment)
        for package in self.packages:
            db.session.delete(package)
        for screenshot in self.screenshots:
            db.session.delete(screenshot)
        db.session.delete(self)

    def url(self, **kwargs):
        return url_for("show_game",
                       jam_slug=self.jam.slug,
                       game_id=self.id,
                       **kwargs)

    @property
    def screenshots_ordered(self):
        return sorted(self.screenshots, key=lambda s: s.index)

    @property
    def score(self):
        if self.has_cheated:
            return -10

        return average(
            [r.score for r in self.ratings if not r.user.is_deleted]) or 0

    def feedback_average(self, category):
        if category in (None, "overall"):
            return self.score
        return average_non_zero([r.get(category) for r in self.ratings])

    @property
    def rank(self):
        jam_games = list(self.jam.games.all())
        jam_games.sort(key="score", reverse=True)
        return jam_games.index(self) + 1

    @property
    def number_ratings(self):
        return len(self.ratings)

    @property
    def rating_categories(self):
        return [
            c for c in RATING_CATEGORIES
            if getattr(self, "score_" + c + "_enabled")
        ]

    def get_rating_by_user(self, user):
        return Rating.query.filter_by(user_id=user.id).first()
Beispiel #21
0
    def feedback_average(self, category):
        if category in (None, "overall"):
            return self.score
        return average_non_zero([r.get(category) for r in self.ratings])

    @property
    def rank(self):
        jam_games = list(self.jam.games.all())
        jam_games.sort(key="score", reverse=True)
        return jam_games.index(self) + 1

    @property
    def number_ratings(self):
        return len(self.ratings)

    @property
    def rating_categories(self):
        return [
            c for c in RATING_CATEGORIES
            if getattr(self, "score_" + c + "_enabled")
        ]

    def get_rating_by_user(self, user):
        return Rating.query.filter_by(user_id=user.id).first()


# Adds fields "dynamically" (which score categories are enabled?)
for c in RATING_CATEGORIES:
    setattr(Game, f"score_{c}_enabled", db.Column(db.Boolean, default=True))
Beispiel #22
0
class GamePackage(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(255))
    game_id = db.Column(db.Integer, db.ForeignKey("game.id"))
    type = db.Column(
        db.Enum(
            "web",  # Flash, html5, js...
            "linux",  # Linux binaries (e.g. *.tar.gz)
            "linux32",  # Linux32 binaries (e.g. *.tar.gz)
            "linux64",  # Linux64 binaries (e.g. *.tar.gz)
            "windows",  # Windows binaries (e.g. *.zip, *.exe)
            "windows64",  # Windows64 binaries (e.g. *.zip, *.exe)
            "mac",  # MacOS application packages
            "combi",  # Linux + Windows + Source (and more, optional)
            "love",  # Löve packages
            "blender",  # Blender save file (*.blend)
            "source",  # Source package (e.g. *.zip or *.tar.gz)
            "git",  # Version control repository: GIT
            "svn",  # Version control repository: SVN
            "hg",  # Version control repository: HG
            "unknown"))

    def __init__(self, game, url, type="unknown"):
        self.url = url
        self.type = type
        self.game = game

    def getLink(self):
        return Markup('<a href="%s" target="_blank">%s</a>' %
                      (self.url, GamePackage.typeString(self.type)))

    def getLinkShort(self):
        return Markup('<a href="%s">%s</a>' %
                      (self.url, GamePackage.typeStringShort(self.type)))

    def __repr__(self):
        return "<GamePackage %r>" % self.id

    @staticmethod
    def typeString(type):
        if type in PACKAGE_TYPES:
            return PACKAGE_TYPES[type][0]
        return "Unknown"

    @staticmethod
    def typeStringShort(type):
        if type in PACKAGE_TYPES:
            return PACKAGE_TYPES[type][1]
        return "Unknown"

    @staticmethod
    def packageTypes():
        return PACKAGE_TYPES

    @staticmethod
    def compare(left, right):
        x = right.getTotalScore() - left.getTotalScore()
        if x > 0:
            return 1
        elif x < 0:
            return -1
        else:
            return 0
Beispiel #23
0
from hashlib import sha512, md5
from flamejam import app, db, filters
from flask import url_for, Markup
import re
import random

# rating:
# Participant <one2many> RatingSkip <many2one> Entry
# Participant <one2many> Rating <many2one> Entry

# Teams:
# Participant <many2many> Entry

team_members = db.Table(
    'team_members',
    db.Column('entry_id', db.Integer, db.ForeignKey('entry.id')),
    db.Column('participant_id', db.Integer, db.ForeignKey('participant.id')),
)


def get_slug(s):
    s = s.lower()
    s = re.sub(r"[\s_+]+", "-", s)
    s = re.sub("[^a-z0-9\-]", "", s)
    return s


class Participant(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    password = db.Column(db.String(128))
Beispiel #24
0
class Jam(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    slug = db.Column(db.String(128), unique=True)
    title = db.Column(db.String(128), unique=True)
    theme = db.Column(db.String(128))
    announced = db.Column(db.DateTime)  # Date on which the jam was announced
    start_time = db.Column(db.DateTime)  # The jam starts at this moment
    end_time = db.Column(db.DateTime)  # The jamming phase ends at this moment
    packaging_deadline = db.Column(
        db.DateTime)  # Packaging ends at this moment
    rating_end = db.Column(db.DateTime)  # Rating period ends and jam is over
    team_jam = db.Column(db.Boolean)
    entries = db.relationship('Entry', backref='jam', lazy='dynamic')
    author_id = db.Column(db.Integer, db.ForeignKey('participant.id'))

    def __init__(self,
                 title,
                 author,
                 start_time,
                 end_time=None,
                 packaging_deadline=None,
                 voting_end=None,
                 team_jam=False,
                 theme=''):
        self.title = title
        self.slug = get_slug(title)
        self.start_time = start_time
        self.theme = theme
        self.author = author
        self.team_jam = team_jam

        if end_time is None:
            self.end_time = start_time + timedelta(days=2)
        else:
            self.end_time = end_time

        if packaging_deadline is None:
            self.packaging_deadline = start_time + timedelta(days=3)
        else:
            self.packaging_deadline = packaging_deadline

        if self.rating_end is None:
            self.rating_end = start_time + timedelta(days=7)
        else:
            self.rating_end = rating_end

        self.announced = datetime.utcnow()

    def __repr__(self):
        return '<Jam %r>' % self.slug

    def getStatus(self):
        now = datetime.utcnow()
        if self.start_time > now:
            return JamStatus(JamStatusCode.ANNOUNCED, self.start_time)
        elif self.end_time > now:
            return JamStatus(JamStatusCode.RUNNING, self.end_time)
        elif self.packaging_deadline > now:
            return JamStatus(JamStatusCode.PACKAGING, self.packaging_deadline)
        elif self.rating_end > now:
            return JamStatus(JamStatusCode.RATING, self.rating_end)
        else:
            return JamStatus(JamStatusCode.FINISHED, self.end_time)

    def url(self, **values):
        return url_for('show_jam', jam_slug=self.slug, **values)

    def getTopEntries(self):
        e = list(self.entries.all())
        e.sort(cmp=entryCompare)
        return e

    def getShuffledEntries(self):
        e = list(self.entries.all())
        random.shuffle(e)
        return e
Beispiel #25
0
class Entry(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(128))
    slug = db.Column(db.String(128))
    description = db.Column(db.Text)
    posted = db.Column(db.DateTime)
    jam_id = db.Column(db.Integer, db.ForeignKey('jam.id'))
    participant_id = db.Column(db.Integer, db.ForeignKey('participant.id'))
    rating_skips = db.relationship('RatingSkip',
                                   backref='entry',
                                   lazy='dynamic')
    ratings = db.relationship('Rating', backref='entry', lazy='dynamic')
    comments = db.relationship('Comment', backref='entry', lazy='dynamic')
    packages = db.relationship('EntryPackage', backref='entry', lazy='dynamic')
    screenshots = db.relationship('EntryScreenshot',
                                  backref='entry',
                                  lazy='dynamic')

    def __init__(self, title, description, jam, participant):
        self.title = title
        self.slug = get_slug(title)
        self.description = description
        self.jam = jam
        self.participant = participant
        self.posted = datetime.utcnow()

    def __repr__(self):
        return '<Entry %r>' % self.title

    def url(self, action="", **values):
        return url_for("show_entry",
                       jam_slug=self.jam.slug,
                       entry_slug=self.slug,
                       action=action,
                       **values)

    def getAverageRating(self):
        categories = [
            "gameplay", "graphics", "audio", "innovation", "story",
            "technical", "controls", "overall"
        ]
        r = {"average": 0}

        for c in categories:
            r[c] = 0

        ratings = len(self.ratings.all())
        if ratings > 0:
            for rating in self.ratings:
                for c in categories:
                    r[c] += getattr(rating, "score_" + c)
                r["average"] += rating.getAverage()

            for c in categories:
                r[c] *= 1.0 / ratings
            r["average"] *= 1.0 / ratings
        return r

    def getTotalScore(self):
        s = 0
        c = 0
        av = self.getAverageRating()
        for x in av:
            s += av[x]
            c += 1
        return s * 1.0 / c

    def getRank(self):
        jam_entries = list(self.jam.entries.all())
        jam_entries.sort(cmp=entryCompare)
        return jam_entries.index(self) + 1
Beispiel #26
0
class Participant(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    password = db.Column(db.String(128))
    token = db.Column(db.Integer, nullable=True, default=None)
    email = db.Column(db.String(256), unique=True)
    is_admin = db.Column(db.Boolean, default=False)
    is_verified = db.Column(db.Boolean)
    receive_emails = db.Column(db.Boolean)
    registered = db.Column(db.DateTime)
    entries = db.relationship('Entry', backref='participant', lazy='dynamic')
    team_entries = db.relationship("Entry",
                                   secondary=team_members,
                                   backref="team")
    ratings = db.relationship('Rating', backref='participant', lazy='dynamic')
    comments = db.relationship('Comment',
                               backref='participant',
                               lazy='dynamic')
    jams = db.relationship('Jam', backref='author', lazy='dynamic')
    rating_skips = db.relationship('RatingSkip',
                                   backref='participant',
                                   lazy='dynamic')
    ratings = db.relationship('Rating', backref='participant', lazy='dynamic')

    def __init__(self,
                 username,
                 password,
                 email,
                 is_admin=False,
                 is_verified=False,
                 receive_emails=True):
        self.username = username
        self.password = sha512(
            (password + app.config['SECRET_KEY']).encode('utf-8')).hexdigest()
        self.email = email
        self.is_admin = is_admin
        self.is_verified = is_verified
        self.registered = datetime.utcnow()
        self.receive_emails = receive_emails

    def getVerificationHash(self):
        # combine a few properties, hash md5
        # take first 8 chars for simplicity
        return md5(self.username + self.password +
                   app.config['SECRET_KEY']).hexdigest()[:8]

    def getResetToken(self):
        # combine a few properties, hash md5
        # take first 8 chars for simplicity
        return md5(str(self.token) + app.config['SECRET_KEY']).hexdigest()[:8]

    def skippedEntry(self, entry):
        return self.rating_skips.filter_by(entry=entry).first() != None

    def ratedEntry(self, entry):
        return self.ratings.filter_by(entry=entry).first() != None

    def getRatingCount(self, jam):
        i = 0
        for r in self.ratings:
            if r.entry.jam == jam:
                i += 1
        return i

    def getTotalEntryCount(self):
        return len(self.entries.all()) + len(self.team_entries)

    def getSkippedCount(self, jam):
        return len(
            self.rating_skips.filter(RatingSkip.participant_id == self.id
                                     and Entry.jam_id == jam.id).all())

    def __repr__(self):
        return '<User %r>' % self.username

    def url(self, **values):
        return url_for('show_participant', username=self.username, **values)

    def getAvatar(self, size=32):
        return "http://www.gravatar.com/avatar/{0}?s={1}&d=retro".format(
            md5(self.email.lower()).hexdigest(), size)

    def getLink(self, class_=""):
        s = 14
        if self.is_admin:
            class_ += " admin"
        return Markup(
            '<a class="user {4}" href="{0}"><img width="{2}" height="{2}" src="{3}" class="icon"/> {1}</a>'
            .format(self.url(), self.username, s, self.getAvatar(s), class_))

    def canRate(self, entry):
        return entry.participant != self and not self in entry.team

    def canEdit(self, entry):
        return entry.participant == self

    def getEntryInJam(self, jam):
        for entry in self.entries:
            if entry.jam == jam:
                return entry
        return None

    def getTeamEntryInJam(self, jam):
        for entry in self.team_entries:
            if entry.jam == jam:
                return entry
        return None
Beispiel #27
0
class Jam(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    slug = db.Column(db.String(128), unique=True)
    title = db.Column(db.String(128), unique=True)
    theme = db.Column(db.String(128))
    announced = db.Column(db.DateTime)  # Date on which the jam was announced
    start_time = db.Column(db.DateTime)  # The jam starts at this moment
    team_limit = db.Column(db.Integer)  # 0 = no limit
    games = db.relationship('Game', backref="jam", lazy="subquery")
    participations = db.relationship("Participation",
                                     backref="jam",
                                     lazy="subquery")
    teams = db.relationship("Team", backref="jam", lazy="subquery")

    description = db.Column(db.Text)
    restrictions = db.Column(db.Text)

    registration_duration = db.Column(db.Integer)  # hours
    packaging_duration = db.Column(db.Integer)  # hours
    rating_duration = db.Column(db.Integer)  # hours
    duration = db.Column(db.Integer)  # hours

    # last notification that was sent, e.g. 0 = announcement, 1 = registration, (see status codes)
    last_notification_sent = db.Column(db.Integer, default=-1)

    def __init__(self, title, start_time, duration=48, team_limit=0, theme=''):
        self.title = title
        self.slug = get_slug(title)
        self.start_time = start_time
        self.duration = duration
        self.registration_duration = 24 * 14
        self.packaging_duration = 24 * 1
        self.rating_duration = 24 * 5
        self.announced = datetime.utcnow()
        self.theme = theme
        self.team_limit = team_limit

    @property
    def participants(self):
        return [r.user for r in self.participations]

    @property
    def end_time(self):
        return self.start_time + timedelta(hours=self.duration)

    @property
    def packaging_deadline(self):
        return self.end_time + timedelta(hours=self.packaging_duration)

    @property
    def rating_end(self):
        return self.packaging_deadline + timedelta(hours=self.rating_duration)

    @property
    def registration_start(self):
        return self.start_time - timedelta(hours=self.registration_duration)

    def __repr__(self):
        return f"<Jam {self.slug}>"

    def get_status(self):
        now = datetime.utcnow()
        if self.registration_start > now:
            return JamStatus(JamStatusCode.ANNOUNCED, self.start_time)
        elif self.start_time > now:
            return JamStatus(JamStatusCode.REGISTRATION, self.start_time)
        elif self.end_time > now:
            return JamStatus(JamStatusCode.RUNNING, self.end_time)
        elif self.packaging_deadline > now:
            return JamStatus(JamStatusCode.PACKAGING, self.packaging_deadline)
        elif self.rating_end > now:
            return JamStatus(JamStatusCode.RATING, self.rating_end)
        else:
            return JamStatus(JamStatusCode.FINISHED, self.end_time)

    def url(self, **kwargs):
        return url_for('jam_info', jam_slug=self.slug, **kwargs)

    def games_filtered_by_package_types(self, filters):
        games = Game.query.filter_by(is_deleted=False).filter_by(
            jam_id=self.id)
        if filters == set():
            games = games
        elif 'packaged' in filters:
            games = games.join(GamePackage)
        else:
            games = games.filter(
                GamePackage.type.in_(filters)).join(GamePackage)
        return games.all()

    def games_by_score(self, filters=set()):
        e = self.games_filtered_by_package_types(filters)
        e.sort(key=Game.score.fget, reverse=True)
        return e

    def games_by_total_ratings(self, filters=set()):
        e = self.games_filtered_by_package_types(filters)
        e.sort(key=Game.number_ratings.fget)
        return e

    @property
    def show_theme(self):
        return self.get_status().code >= JamStatusCode.RUNNING and self.theme

    @property
    def show_ratings(self):
        return self.get_status().code == JamStatusCode.FINISHED

    def get_link(self):
        s = f'<a class="jam" href="{self.url()}">{self.title}</a>'
        if self.show_theme:
            s += f' <span class="theme">{self.theme}</span>'
        return Markup(s)

    def send_all_notifications(self):
        last = -1
        for n in range(self.last_notification_sent + 1,
                       self.get_status().code + 1):
            if self.send_notification(n):
                last = n
        return last

    def send_notification(self, n):
        if not JamStatusCode.ANNOUNCED <= n <= JamStatusCode.FINISHED:
            return False

        kwargs = {}

        if n == JamStatusCode.ANNOUNCED:
            template = "announcement"
            notify = "new_jam"
            subject = f"Jam announced: {self.title}"
        elif n == JamStatusCode.REGISTRATION:
            template = "registration_start"
            notify = "new_jam"
            subject = f"Registrations for {self.title} now open"
        elif n == JamStatusCode.RUNNING:
            template = "start"
            notify = "jam_start"
            subject = f"{self.title} starts now!"
        elif n == JamStatusCode.PACKAGING:
            template = "packaging_start"
            notify = "jam_finish"
            subject = f"{self.title} is over"
        elif n == JamStatusCode.RATING:
            template = "rating_start"
            notify = "jam_finish"
            subject = f"Rating for {self.title} starts now"
        elif n == JamStatusCode.FINISHED:
            template = "finished"
            notify = "jam_finish"
            subject = f"Rating for {self.title} finished - Winners"
            kwargs = {"games": self.games_by_score()[:3]}

        if n >= JamStatusCode.RUNNING and n != JamStatusCode.RATING:
            users = [r.user for r in self.participations]
        else:
            from flamejam.models.user import User
            users = User.query.all()

        # Set this first because we might send for longer than a minute at which point the
        # next tick will come around.
        self.last_notification_sent = n
        db.session.commit()

        subject = app.config["LONG_NAME"] + ": " + subject

        with mail.connect() as conn:
            for user in users:
                if getattr(user, "notify_" + notify):
                    body = render_template("emails/jam/" + template + ".txt",
                                           recipient=user,
                                           jam=self,
                                           **kwargs)
                    sender = app.config['MAIL_DEFAULT_SENDER']
                    recipients = [user.email]
                    message = Message(subject=subject,
                                      sender=sender,
                                      body=body,
                                      recipients=recipients)
                    try:
                        conn.send(message)
                    except SMTPRecipientsRefused:
                        pass
        return True

    @property
    def livestream_teams(self):
        return [t for t in self.teams if t.livestream]
Beispiel #28
0
class Game(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(128))
    slug = db.Column(db.String(128))
    created = db.Column(db.DateTime)
    description = db.Column(db.Text)
    technology = db.Column(db.Text)
    help = db.Column(db.Text)
    is_deleted = db.Column(db.Boolean, default=False)
    has_cheated = db.Column(db.Boolean, default=False)

    jam_id = db.Column(db.Integer, db.ForeignKey('jam.id'))
    team_id = db.Column(db.Integer, db.ForeignKey('team.id'))
    ratings = db.relationship('Rating', backref='game', lazy="subquery")
    comments = db.relationship('Comment', backref='game', lazy="subquery")
    packages = db.relationship('GamePackage', backref='game', lazy="subquery")
    screenshots = db.relationship('GameScreenshot', backref='game', lazy="subquery")
    votes = db.relationship('Vote', backref='game', lazy="subquery")

    # score_CATEGORY_enabled = db.Column(db.Boolean, default = True)

    def __init__(self, team, title):
        self.team = team
        self.jam = team.jam
        self.title = title
        self.slug = get_slug(title)
        self.created = datetime.utcnow()

    def __repr__(self):
        return '<Game %r>' % self.title

    def destroy(self):
        # destroy all ratings, comments, packages, screenshots
        for rating in self.ratings:
            db.session.delete(rating)
        for comment in self.comments:
            db.session.delete(comment)
        for package in self.packages:
            db.session.delete(package)
        for screenshot in self.screenshots:
            db.session.delete(screenshot)
        for vote in self.votes:
            db.session.delete(vote)
        db.session.delete(self)

    def url(self, **values):
        return url_for("show_game", jam_slug=self.jam.slug, game_id=self.id, **values)

    @property
    def screenshotsOrdered(self):
        return sorted(self.screenshots, lambda s1, s2: int(s1.index - s2.index))

    @property
    def firstScreenshot(self):
        return self.screenshots.first()

    @property
    def score(self):
        if self.has_cheated:
            return -10

        return average([r.score for r in self.ratings if not r.user.is_deleted]) or 0

    def feedbackAverage(self, category):
        if category in (None, "overall"):
            return self.score
        return average_non_zero([r.get(category) for r in self.ratings])

    @property
    def rank(self):
        db.engine.execute("SET @rank=0;")
        rank = db.engine.execute(
            "SELECT rank FROM (SELECT @rank:=@rank+1 AS rank, title, gameId, points FROM (SELECT v.game_id as gameId, g.title as title, count(*) as points FROM vote v LEFT JOIN game g ON g.id = v.game_id where v.jam_id = " + str(
                self.jam_id) + " GROUP BY v.game_id ORDER BY points DESC) t1) t2 WHERE gameId = " + str(self.id)).first()
        return rank.rank

    @property
    def numberRatings(self):
        return len(self.ratings)

    @property
    def numberVotes(self):
        return len(self.votes)

    def getVoteByUser(self, user):
        return Vote.query.filter_by(user_id=user.id).first()

    def getVoteCountByUser(self, user):
        return Vote.query.filter_by(user_id=user.id, jam_id=self.jam_id).count()

    @property
    def ratingCategories(self):
        return [c for c in RATING_CATEGORIES if getattr(self, "score_" + c + "_enabled")]

    def getRatingByUser(self, user):
        return Rating.query.filter_by(user_id=user.id).first()