Пример #1
0
class Sport(db.Model):
    __tablename__ = "sports"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    label = db.Column(db.String(50), unique=True, nullable=False)
    img = db.Column(db.String(255), unique=True, nullable=True)
    is_default = db.Column(db.Boolean, default=False, nullable=False)
    activities = db.relationship('Activity',
                                 lazy=True,
                                 backref=db.backref('sports', lazy='joined'))
    records = db.relationship('Record',
                              lazy=True,
                              backref=db.backref('sports', lazy='joined'))

    def __repr__(self):
        return f'<Sport {self.label!r}>'

    def __init__(self, label):
        self.label = label

    def serialize(self):
        return {
            'id': self.id,
            'label': self.label,
            'img': self.img,
            '_can_be_deleted': len(self.activities) == 0
            and not self.is_default,
        }
Пример #2
0
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password = db.Column(db.String(255), nullable=False)
    created_at = db.Column(db.DateTime, nullable=False)
    admin = db.Column(db.Boolean, default=False, nullable=False)
    first_name = db.Column(db.String(80), nullable=True)
    last_name = db.Column(db.String(80), nullable=True)
    birth_date = db.Column(db.DateTime, nullable=True)
    location = db.Column(db.String(80), nullable=True)
    bio = db.Column(db.String(200), nullable=True)
    picture = db.Column(db.String(255), nullable=True)
    timezone = db.Column(db.String(50), nullable=True)
    activities = db.relationship('Activity',
                                 lazy=True,
                                 backref=db.backref('users', lazy='joined'))
    records = db.relationship('Record',
                              lazy=True,
                              backref=db.backref('users', lazy='joined'))

    def __repr__(self):
        return f'<User {self.username!r}>'

    def __init__(self,
                 username,
                 email,
                 password,
                 created_at=datetime.datetime.utcnow()):
        self.username = username
        self.email = email
        self.password = bcrypt.generate_password_hash(
            password, current_app.config.get('BCRYPT_LOG_ROUNDS')).decode()
        self.created_at = created_at

    @staticmethod
    def encode_auth_token(user_id):
        """
        Generates the auth token
        :param user_id: -
        :return: JWToken
        """
        try:
            payload = {
                'exp':
                datetime.datetime.utcnow() + datetime.timedelta(
                    days=current_app.config.get('TOKEN_EXPIRATION_DAYS'),
                    seconds=current_app.config.get(
                        'TOKEN_EXPIRATION_SECONDS')),
                'iat':
                datetime.datetime.utcnow(),
                'sub':
                user_id
            }
            return jwt.encode(payload,
                              current_app.config.get('SECRET_KEY'),
                              algorithm='HS256')
        except Exception as e:
            return e

    @staticmethod
    def decode_auth_token(auth_token):
        """
        Decodes the auth token
        :param auth_token: -
        :return: integer|string
        """
        try:
            payload = jwt.decode(auth_token,
                                 current_app.config.get('SECRET_KEY'))
            return payload['sub']
        except jwt.ExpiredSignatureError:
            return 'Signature expired. Please log in again.'
        except jwt.InvalidTokenError:
            return 'Invalid token. Please log in again.'

    def serialize(self):
        nb_activity = Activity.query.filter(
            Activity.user_id == self.id).count()
        sports = []
        total = (None, None)
        if nb_activity > 0:
            sports = db.session.query(func.count(Activity.sport_id)).group_by(
                Activity.sport_id).all()
            total = db.session.query(func.sum(Activity.distance),
                                     func.sum(Activity.duration)).first()
        return {
            'id': self.id,
            'username': self.username,
            'email': self.email,
            'created_at': self.created_at,
            'admin': self.admin,
            'first_name': self.first_name,
            'last_name': self.last_name,
            'bio': self.bio,
            'location': self.location,
            'birth_date': self.birth_date,
            'picture': self.picture is not None,
            'timezone': self.timezone,
            'nb_activities': nb_activity,
            'nb_sports': len(sports),
            'total_distance': float(total[0]) if total[0] else 0,
            'total_duration': str(total[1]) if total[1] else "0:00:00",
        }
Пример #3
0
class Activity(db.Model):
    __tablename__ = "activities"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    sport_id = db.Column(db.Integer,
                         db.ForeignKey('sports.id'),
                         nullable=False)
    title = db.Column(db.String(255), nullable=True)
    gpx = db.Column(db.String(255), nullable=True)
    creation_date = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    modification_date = db.Column(db.DateTime,
                                  onupdate=datetime.datetime.utcnow)
    activity_date = db.Column(db.DateTime, nullable=False)
    duration = db.Column(db.Interval, nullable=False)
    pauses = db.Column(db.Interval, nullable=True)
    moving = db.Column(db.Interval, nullable=True)
    distance = db.Column(db.Numeric(6, 3), nullable=True)  # kilometers
    min_alt = db.Column(db.Numeric(6, 2), nullable=True)  # meters
    max_alt = db.Column(db.Numeric(6, 2), nullable=True)  # meters
    descent = db.Column(db.Numeric(7, 2), nullable=True)  # meters
    ascent = db.Column(db.Numeric(7, 2), nullable=True)  # meters
    max_speed = db.Column(db.Numeric(6, 2), nullable=True)  # km/h
    ave_speed = db.Column(db.Numeric(6, 2), nullable=True)  # km/h
    bounds = db.Column(postgresql.ARRAY(db.Float), nullable=True)
    map = db.Column(db.String(255), nullable=True)
    map_id = db.Column(db.String(50), nullable=True)
    weather_start = db.Column(JSON, nullable=True)
    weather_end = db.Column(JSON, nullable=True)
    notes = db.Column(db.String(500), nullable=True)
    segments = db.relationship(
        'ActivitySegment',
        lazy=True,
        cascade='all, delete',
        backref=db.backref('activities', lazy='joined', single_parent=True),
    )
    records = db.relationship(
        'Record',
        lazy=True,
        cascade='all, delete',
        backref=db.backref('activities', lazy='joined', single_parent=True),
    )

    def __str__(self):
        return f'<Activity \'{self.sports.label}\' - {self.activity_date}>'

    def __init__(self, user_id, sport_id, activity_date, distance, duration):
        self.user_id = user_id
        self.sport_id = sport_id
        self.activity_date = activity_date
        self.distance = distance
        self.duration = duration

    def serialize(self, params=None):
        date_from = params.get('from') if params else None
        date_to = params.get('to') if params else None
        distance_from = params.get('distance_from') if params else None
        distance_to = params.get('distance_to') if params else None
        duration_from = params.get('duration_from') if params else None
        duration_to = params.get('duration_to') if params else None
        ave_speed_from = params.get('ave_speed_from') if params else None
        ave_speed_to = params.get('ave_speed_to') if params else None
        max_speed_from = params.get('max_speed_from') if params else None
        max_speed_to = params.get('max_speed_to') if params else None
        sport_id = params.get('sport_id') if params else None
        previous_activity = (Activity.query.filter(
            Activity.id != self.id,
            Activity.user_id == self.user_id,
            Activity.sport_id == sport_id if sport_id else True,
            Activity.activity_date <= self.activity_date,
            Activity.activity_date >= datetime.datetime.strptime(
                date_from, '%Y-%m-%d') if date_from else True,
            Activity.activity_date <= datetime.datetime.strptime(
                date_to, '%Y-%m-%d') if date_to else True,
            Activity.distance >= int(distance_from) if distance_from else True,
            Activity.distance <= int(distance_to) if distance_to else True,
            Activity.duration >= convert_in_duration(duration_from)
            if duration_from else True,
            Activity.duration <= convert_in_duration(duration_to)
            if duration_to else True,
            Activity.ave_speed >= float(ave_speed_from)
            if ave_speed_from else True,
            Activity.ave_speed <= float(ave_speed_to)
            if ave_speed_to else True,
            Activity.max_speed >= float(max_speed_from)
            if max_speed_from else True,
            Activity.max_speed <= float(max_speed_to)
            if max_speed_to else True,
        ).order_by(Activity.activity_date.desc()).first())
        next_activity = (Activity.query.filter(
            Activity.id != self.id,
            Activity.user_id == self.user_id,
            Activity.sport_id == sport_id if sport_id else True,
            Activity.activity_date >= self.activity_date,
            Activity.activity_date >= datetime.datetime.strptime(
                date_from, '%Y-%m-%d') if date_from else True,
            Activity.activity_date <= datetime.datetime.strptime(
                date_to, '%Y-%m-%d') if date_to else True,
            Activity.distance >= int(distance_from) if distance_from else True,
            Activity.distance <= int(distance_to) if distance_to else True,
            Activity.duration >= convert_in_duration(duration_from)
            if duration_from else True,
            Activity.duration <= convert_in_duration(duration_to)
            if duration_to else True,
            Activity.ave_speed >= float(ave_speed_from)
            if ave_speed_from else True,
            Activity.ave_speed <= float(ave_speed_to)
            if ave_speed_to else True,
        ).order_by(Activity.activity_date.asc()).first())
        return {
            "id":
            self.id,
            "user_id":
            self.user_id,
            "sport_id":
            self.sport_id,
            "title":
            self.title,
            "creation_date":
            self.creation_date,
            "modification_date":
            self.modification_date,
            "activity_date":
            self.activity_date,
            "duration":
            str(self.duration) if self.duration else None,
            "pauses":
            str(self.pauses) if self.pauses else None,
            "moving":
            str(self.moving) if self.moving else None,
            "distance":
            float(self.distance) if self.distance else None,
            "min_alt":
            float(self.min_alt) if self.min_alt else None,
            "max_alt":
            float(self.max_alt) if self.max_alt else None,
            "descent":
            float(self.descent) if self.descent else None,
            "ascent":
            float(self.ascent) if self.ascent else None,
            "max_speed":
            float(self.max_speed) if self.max_speed else None,
            "ave_speed":
            float(self.ave_speed) if self.ave_speed else None,
            "with_gpx":
            self.gpx is not None,
            "bounds":
            [float(bound)
             for bound in self.bounds] if self.bounds else [],  # noqa
            "previous_activity":
            previous_activity.id if previous_activity else None,  # noqa
            "next_activity":
            next_activity.id if next_activity else None,
            "segments": [segment.serialize() for segment in self.segments],
            "records": [record.serialize() for record in self.records],
            "map":
            self.map_id if self.map else None,
            "weather_start":
            self.weather_start,
            "weather_end":
            self.weather_end,
            "notes":
            self.notes,
        }

    @classmethod
    def get_user_activity_records(cls, user_id, sport_id, as_integer=False):
        record_types_columns = {
            'AS': 'ave_speed',  # 'Average speed'
            'FD': 'distance',  # 'Farthest Distance'
            'LD': 'moving',  # 'Longest Duration'
            'MS': 'max_speed',  # 'Max speed'
        }
        records = {}
        for record_type, column in record_types_columns.items():
            column_sorted = getattr(getattr(Activity, column), 'desc')()
            record_activity = (Activity.query.filter_by(
                user_id=user_id,
                sport_id=sport_id).order_by(column_sorted,
                                            Activity.activity_date).first())
            records[record_type] = dict(
                record_value=(getattr(record_activity, column)
                              if record_activity else None),
                activity=record_activity,
            )
        return records
Пример #4
0
class Record(db.Model):
    __tablename__ = "records"
    __table_args__ = (db.UniqueConstraint('user_id',
                                          'sport_id',
                                          'record_type',
                                          name='user_sports_records'), )
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    sport_id = db.Column(db.Integer,
                         db.ForeignKey('sports.id'),
                         nullable=False)
    activity_id = db.Column(db.Integer,
                            db.ForeignKey('activities.id'),
                            nullable=False)
    record_type = db.Column(Enum(*record_types, name="record_types"))
    activity_date = db.Column(db.DateTime, nullable=False)
    _value = db.Column("value", db.Integer, nullable=True)

    def __str__(self):
        return (f'<Record {self.sports.label} - '
                f'{self.record_type} - '
                f"{self.activity_date.strftime('%Y-%m-%d')}>")

    def __init__(self, activity, record_type):
        self.user_id = activity.user_id
        self.sport_id = activity.sport_id
        self.activity_id = activity.id
        self.record_type = record_type
        self.activity_date = activity.activity_date

    @hybrid_property
    def value(self):
        if self._value is None:
            return None
        if self.record_type == 'LD':
            return datetime.timedelta(seconds=self._value)
        elif self.record_type in ['AS', 'MS']:
            return float(self._value / 100)
        else:  # 'FD'
            return float(self._value / 1000)

    @value.setter
    def value(self, val):
        self._value = convert_value_to_integer(self.record_type, val)

    def serialize(self):
        if self.value is None:
            value = None
        elif self.record_type in ['AS', 'FD', 'MS']:
            value = float(self.value)
        else:  # 'LD'
            value = str(self.value)

        return {
            "id": self.id,
            "user_id": self.user_id,
            "sport_id": self.sport_id,
            "activity_id": self.activity_id,
            "record_type": self.record_type,
            "activity_date": self.activity_date,
            "value": value,
        }
Пример #5
0
class ActivitySegment(db.Model):
    __tablename__ = "activity_segments"
    activity_id = db.Column(db.Integer,
                            db.ForeignKey('activities.id'),
                            primary_key=True)
    segment_id = db.Column(db.Integer, primary_key=True)
    duration = db.Column(db.Interval, nullable=False)
    pauses = db.Column(db.Interval, nullable=True)
    moving = db.Column(db.Interval, nullable=True)
    distance = db.Column(db.Numeric(6, 3), nullable=True)  # kilometers
    min_alt = db.Column(db.Numeric(6, 2), nullable=True)  # meters
    max_alt = db.Column(db.Numeric(6, 2), nullable=True)  # meters
    descent = db.Column(db.Numeric(7, 2), nullable=True)  # meters
    ascent = db.Column(db.Numeric(7, 2), nullable=True)  # meters
    max_speed = db.Column(db.Numeric(6, 2), nullable=True)  # km/h
    ave_speed = db.Column(db.Numeric(6, 2), nullable=True)  # km/h

    def __str__(self):
        return (f'<Segment \'{self.segment_id}\' '
                f'for activity \'{self.activity_id}\'>')

    def __init__(self, segment_id, activity_id):
        self.segment_id = segment_id
        self.activity_id = activity_id

    def serialize(self):
        return {
            "activity_id": self.activity_id,
            "segment_id": self.segment_id,
            "duration": str(self.duration) if self.duration else None,
            "pauses": str(self.pauses) if self.pauses else None,
            "moving": str(self.moving) if self.moving else None,
            "distance": float(self.distance) if self.distance else None,
            "min_alt": float(self.min_alt) if self.min_alt else None,
            "max_alt": float(self.max_alt) if self.max_alt else None,
            "descent": float(self.descent) if self.descent else None,
            "ascent": float(self.ascent) if self.ascent else None,
            "max_speed": float(self.max_speed) if self.max_speed else None,
            "ave_speed": float(self.ave_speed) if self.ave_speed else None,
        }