Ejemplo n.º 1
0
class Post(db.Model):
    __abstract__ = True
    id = db.Column(db.Integer, primary_key=True)

    body = db.Column(db.String(140))

    creation_date = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    update_date = db.Column(db.DateTime, index=True, default=datetime.utcnow)

    def __repr__(self):
        return '<Post {}>'.format(self.body)
Ejemplo n.º 2
0
class UserPost(Post):
    """
    User's post for post news.
    """
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return '<UserPost {}>'.format(self.body)
Ejemplo n.º 3
0
class RosterPost(Post):
    """
    Roster's post
    """

    roster_id = db.Column(db.Integer, db.ForeignKey('roster.id'))

    def __repr__(self):
        return '<RosterPost {}>'.format(self.body)
Ejemplo n.º 4
0
class GuildPost(Post):
    """
    Guild's post
    """

    guild_id = db.Column(db.Integer, db.ForeignKey('guild.id'))

    def __repr__(self):
        return '<GuildPost {}>'.format(self.body)
Ejemplo n.º 5
0
class User(PaginateAPIMixin, UserMixin, db.Model):
    """
    User model Class.
    A User can Follow / Unfollow an other User.
    A User can Follow / Unfollow some Guild
    A User can Create or Delete some Roster
    """
    id = db.Column(db.Integer, primary_key=True)

    username = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    password_hash = db.Column(db.String(128))
    about_me = db.Column(db.String(140))

    token = db.Column(db.String(32), index=True, unique=True)
    token_expiration = db.Column(db.DateTime)

    posts = db.relationship('UserPost', backref='author', lazy='dynamic')
    rosters = db.relationship('Roster', backref='owner', lazy='dynamic')
    followed = db.relationship('User',
                               secondary=followers,
                               primaryjoin=(followers.c.follower_id == id),
                               secondaryjoin=(followers.c.followed_id == id),
                               backref=db.backref('followers', lazy='dynamic'),
                               lazy='dynamic')
    guilds_followed = db.relationship('Guild',
                                      secondary=guild_followers,
                                      backref=db.backref('followers',
                                                         lazy='dynamic'),
                                      lazy='dynamic')

    last_seen = db.Column(db.DateTime, default=datetime.utcnow)

    def __repr__(self):
        return '<User {}>'.format(self.username)

    def to_dict(self, include_email=False):
        """
        Return all Users informations in a dict.
        :param include_email: If True, return also the email adress.
        :return: Dict with user's information for API Response.
        """
        data = {
            'id': self.id,
            'username': self.username,
            'last_seen': self.last_seen.isoformat() + 'Z',
            'about_me': self.about_me,
            'post_count': self.posts.count(),
            'follower_count': self.followers.count(),
            'followed_count': self.followed.count(),
            '_links': {
                'self': url_for('api.get_user', name=self.username),
                'followers': url_for('api.get_followers', name=self.username),
                'followed': url_for('api.get_followed', name=self.username),
                'avatar': self.avatar(128)
            }
        }
        if include_email:
            data['email'] = self.email
        return data

    def from_dict(self, data, new_user=False):
        """
        Load users information by a Dict for User creation or Edit.
        :param data: Dict with informations to change.
        :param new_user: if True, change the password.
        :return: None
        """
        for field in ['username', 'email', 'about_me']:
            if field in data:
                setattr(self, field, data[field])
        if new_user and 'password' in data:
            self.set_password(data['password'])

    def set_password(self, password):
        """
        Generate a new password_hash.
        :param password: New password in clear.
        :return: None
        """
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        """
        Check if password is ok.
        :param password: password in clean
        :return: True or False
        """
        return check_password_hash(self.password_hash, password)

    def avatar(self, size):
        """
        Return gravatar link to User's avatar with his email.
        :param size: Size for the avatar.
        :return: Avatar links in string.
        """
        digest = md5(self.email.lower().encode('utf-8')).hexdigest()
        return 'https://www.gravatar.com/avatar/{}?d=identicon&s={}'.format(
            digest, size)

    def get_token(self, expires_in=3600):
        """
        Get the authentification user Token, or create him.
        :param expires_in: int for expiration token in Seconds.
        :return: User.token string.
        """
        now = datetime.utcnow()
        if self.token and self.token_expiration > now + timedelta(seconds=60):
            return self.token
        self.token = base64.b16encode(os.urandom(24)).decode('utf-8')
        self.token_expiration = now + timedelta(seconds=expires_in)
        db.session.add(self)
        return self.token

    def revoke_token(self):
        """
        Change expiration date to now -1 for the Token.
        :return: None
        """
        self.token_expiration = datetime.utcnow() - timedelta(seconds=1)

    @staticmethod
    def from_token(token):
        """
        Get an User from a Auth Token.
        :param token: String with authentification Token.
        :return: User object or None
        """
        user = User.query.filter_by(token=token).first()
        if user is None or user.token_expiration < datetime.utcnow():
            return None
        return user

    def follow(self, user):
        """
        Follow an User
        :param user: User Object
        :return: None
        """
        if not self.is_following(user):
            self.followed.append(user)

    def unfollow(self, user):
        """
        Unfollow an User.
        :param user: User Object
        :return: None
        """
        if self.is_following(user):
            self.followed.remove(user)

    def is_following(self, user):
        """
        Check if User follow an other User.
        :param user: User object
        :return: True or False
        """
        return self.followed.filter(
            followers.c.followed_id == user.id).count() > 0

    def followed_posts(self):
        """
        Get all followed_posts
        :return: List of Post Object.
        """
        # TODO A voir avec la refonte des posts.
        followed = UserPost.query.join(
            followers, (followers.c.followed_id == UserPost.user_id)).filter(
                followers.c.follower_id == self.id)
        own = UserPost.query.filter_by(user_id=self.id)
        return followed.union(own).order_by(UserPost.creation_date.desc())

    def follow_guild(self, guild):
        """
        Follow a Guild
        :param guild: Guild Object
        :return: None
        """
        if not self.is_following_guild(guild):
            self.guilds_followed.append(guild)

    def unfollow_guild(self, guild):
        """
        Unfollow a Guild.
        :param guild: Guild Object
        :return: None
        """
        if self.is_following_guild(guild):
            self.guilds_followed.remove(guild)

    def is_following_guild(self, guild):
        """
        Return true if the Guild Object is followed by User.
        :param guild: Guild Object
        :return: True or False.
        """
        return self.guilds_followed.filter(
            guild_followers.c.guild_id == guild.id).count() > 0

    def followed_guilds(self):
        """
        Return the guilds followed by User.
        :return: List of Guild object.
        """
        return self.guilds_followed.all()

    def add_roster(self, roster):
        """
        Link a Roster to the User.
        :param roster: Roster object
        :return: None
        """
        if roster not in self.rosters:
            self.rosters.append(roster)

    def del_roster(self, roster):
        """
        Delete a roster created by User.
        :param roster: Roster object.
        :return: None
        """
        # TODO A voir a prendre le nom, plutot que l'object user.
        # TODO A voir a Deprecated, pour utiliser db.session.delete() dans les methodes.
        self.rosters.remove(roster)

    def get_roster(self, name):
        """
        Get a roster created by User by his name.
        :param name: String with the name of the Roster
        :return: Roster object, or None.
        """
        for roster in self.rosters:
            if roster.name == name:
                return roster
        return None
Ejemplo n.º 6
0
from viewcraft import db, login
from datetime import datetime, timedelta
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from hashlib import md5
from flask import url_for
import base64
import os
from viewcraft.models.paginate import PaginateAPIMixin
from viewcraft.models.post import UserPost

followers = db.Table(
    'followers', db.Column('follower_id', db.Integer,
                           db.ForeignKey('user.id')),
    db.Column('followed_id', db.Integer, db.ForeignKey('user.id')))

guild_followers = db.Table(
    'guild_followers',
    db.Column('guild_id', db.Integer, db.ForeignKey('guild.id')),
    db.Column('follower_id', db.Integer, db.ForeignKey('user.id')))


@login.user_loader
def load_user(id):
    return User.query.get(int(id))


class User(PaginateAPIMixin, UserMixin, db.Model):
    """
    User model Class.
    A User can Follow / Unfollow an other User.
Ejemplo n.º 7
0
class Guild(db.Model):
    """
    Guild Model Class.
    A Guild can be followed by multiples Users.
    A Guild can create GuildPost for News.
    A Guild can be linked to multiples Character.
    """
    id = db.Column(db.Integer, primary_key=True)

    name = db.Column(db.String(24))
    realm = db.Column(db.String(24))
    region = db.Column(db.String(24))

    armory_link = db.Column(db.String(280))
    wowprogress_link = db.Column(db.String(280))

    members = db.relationship('Character', backref='guild', lazy='dynamic')
    posts = db.relationship('GuildPost', backref='author', lazy='dynamic')

    creation_date = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    update_date = db.Column(db.DateTime, index=True, default=datetime.utcnow)

    # TODO Voir comment stocker le progress de la guilde.

    def __repr__(self):
        return '<Guild {}:{}:{}>'.format(self.region, self.realm, self.name)

    def add_member(self, character):
        """
        Add a new Character to the guild.
        :param character: Character object.
        :return: None
        """
        self.members.append(character)

    def del_member(self, character):
        """
        Delete a Character in the guild.
        :param character: Character object to del of the Guild.
        :return: None
        """
        self.members.remove(character)

    @property
    def infos(self):
        return self.name, self.realm

    def check_leaver(self):
        guild = bnet.get_guild(self.realm, self.name)
        listName = []
        for member in guild['members']:
            if member['level'] == 120:
                listName.append((member['name'], member['realm']))
        for member in self.members:
            if member.infos not in listName:
                # TODO Add GuildPost for Leave
                self.members.del_member(member)
            listName.remove(member.infos)
        for infos in listName:
            char = get_character(infos[0].infos[1])
            if not char:
                continue
            self.add_member(char)
            # TODO post un GuildPost for Join

    def refresh(self):
        for char in self.members:
            try:
                char.refresh()
            except ValueError as e:
                raise ValueError(e)

    def post_update(self, character):
        # TODO Creer un GuildPost affichant le leaver/joiner/downdunboss
        pass

    def get_news(self, all=False):
        """
        Return weekly guildPosts posted by the guild.
        :param all: Return All the guild posts.
        :return: List of guildPost objects.
        """
        # TODO Ajouter la fonction Get news
        return []
Ejemplo n.º 8
0
class Character(db.Model):
    """
    Character Models Class.
    A character can be in a multiple Roster, and One guild.
    No CharacterPost.
    """
    id = db.Column(db.Integer, primary_key=True)

    name = db.Column(db.String(24))
    realm = db.Column(db.String(24))
    region = db.Column(db.String(24))

    classe = db.Column(db.String(24))
    race = db.Column(db.String(24))

    level = db.Column(db.Integer)
    ilevel = db.Column(db.Float)
    rio_score = db.Column(db.Integer)

    guild_id = db.Column(db.Integer, db.ForeignKey('guild.id'))

    armory_link = db.Column(db.String(280))
    rio_link = db.Column(db.String(280))
    wlog_link = db.Column(db.String(280))

    creation_date = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    update_date = db.Column(db.DateTime, index=True)

    def __repr__(self):
        return '<Character {}:{}:{}>'.format(self.region, self.realm,
                                             self.name)

    def to_dict(self):
        data = {
            'name': self.name,
            'realm': self.realm,
            'region': self.region,
            'class': self.classe,
            'race': self.race,
            'level': self.level,
            'ilevel': self.ilevel,
            'rio_score': self.rio_score,
            '_links': {
                'armory': self.armory_link,
                'raiderio': self.rio_link,
                'warcraftlog': self.wlog_link
            }
        }
        return data

    @property
    def infos(self):
        return self.name, self.realm

    def refresh(self, index=0, created=False):
        """
        Refresh all web-data of the character.
        :param index: For retry the bnet request who sometimes failed.
        :param roster: For only refresh the data for the Roster, and not all the character.
        :param created: For force refresh after creation.
        :return: None
        """
        #        if (self.update_date + timedelta(days=1)) > datetime.utcnow() and not created:
        #            return
        if index > 3:
            return
        self.region = bnet.region
        r = bnet.get_character(self.realm, self.name, "items")
        if r.status_code != 200:
            raise ValueError(r.json())
        r = r.json()
        self.ilevel = int(r["items"]['averageItemLevelEquipped'])
        self.level = int(r['level'])
        self.classe = CLASS[int(r["class"])]
        self.race = RACE[int(r["race"])]
        self.armory_link = "https://worldofwarcraft.com/fr-fr/character/{}/{}".format(
            self.realm.replace(' ', '-'), self.name)
        url = 'https://raider.io/api/v1/characters/profile?region={}&realm={}&name={}&fields=mythic_plus_scores'.format(
            bnet.region, self.realm, self.name)
        r = requests.get(url)
        if r.status_code != 200:
            self.rio_score = 0
        else:
            r = r.json()
            self.rio_score = r["mythic_plus_scores"]["all"]
            self.rio_link = r["profile_url"]
        self.wlog_link = "https://www.warcraftlogs.com/character/{}/{}/{}".format(
            bnet.region, self.realm.replace(' ', '-'), self.name)
        self.update_date = datetime.now()
Ejemplo n.º 9
0
class Roster(db.Model):
    """
    Roster model Class.
    A Roster can have multiples Character
    A Roster can be link to only one User
    A Roster can be followed by multiples users
    A Roster can post RosterPost
    """
    id = db.Column(db.Integer, primary_key=True)

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

    ilvl_average = db.Column(db.Float, default=0)

    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    members = db.relationship('Character',
                              secondary=roster_member,
                              backref=db.backref('rosters', lazy='dynamic'),
                              lazy='dynamic')
    posts = db.relationship('RosterPost', backref='author', lazy='dynamic')

    creation_date = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    update_date = db.Column(db.DateTime, index=True, default=datetime.utcnow)

    def to_dict(self, characters=False):
        data = {
            'id': self.id,
            'name': self.name,
            'post_count': self.posts.count(),
            'ilvl_average': self.ilvl_average,
            '_links': {
                'self': url_for('api.rosters_specific_roster', name=self.name),
                'characters': url_for('api.rosters_roster_members',
                                      name=self.name)
            }
        }
        if characters:
            char_data = []
            for char in self.members:
                char_data.append(char.to_dict())
            data['members'] = char_data
        return data

    def __repr__(self):
        return '<Roster {}>'.format(self.name)

    def add_member(self, character, create=False):
        """
        Add a Character in the Roster.
        :param character: Character object
        :param create: If true, dont create RosterPost for members.
        :return: None
        """
        if not create:
            # TODO Ajouter un RosterPost
            pass
        if not self.is_in_roster(character):
            self.ilvl_average = (self.ilvl_average * self.length() +
                                 character.ilevel) / (self.length() + 1)
            self.members.append(character)

    def del_member(self, character):
        """
        Delete a Character in the Roster.
        :param character: Character object
        :return: None
        """
        # TODO Ajouter un RosterPost
        if self.is_in_roster(character):
            if self.length() == 1:
                self.ilvl_average = 0
            else:
                self.ilvl_average = (self.ilvl_average * self.length() -
                                     character.ilevel) / (self.length() - 1)
            self.members.remove(character)

    def is_in_roster(self, character):
        """
        Return the Character state from the Roster.
        :param character: Character Object
        :return: True if character is in Roster, else False.
        """
        return self.members.filter(
            roster_member.c.character_id == character.id).count() > 0

    def length(self):
        return self.members.count()

    def refresh(self):
        for char in self.members:
            try:
                char.refresh()
            except ValueError as e:
                raise ValueError(e)
Ejemplo n.º 10
0
from viewcraft import db
from datetime import datetime
from flask import url_for

roster_member = db.Table(
    'roster_member',
    db.Column('roster_id', db.Integer, db.ForeignKey('roster.id')),
    db.Column('character_id', db.Integer, db.ForeignKey('character.id')))


class Roster(db.Model):
    """
    Roster model Class.
    A Roster can have multiples Character
    A Roster can be link to only one User
    A Roster can be followed by multiples users
    A Roster can post RosterPost
    """
    id = db.Column(db.Integer, primary_key=True)

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

    ilvl_average = db.Column(db.Float, default=0)

    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    members = db.relationship('Character',
                              secondary=roster_member,
                              backref=db.backref('rosters', lazy='dynamic'),
                              lazy='dynamic')
    posts = db.relationship('RosterPost', backref='author', lazy='dynamic')