2020-05-10 17:08:18 +02:00
|
|
|
from datetime import datetime
|
2017-12-16 21:00:46 +01:00
|
|
|
|
|
|
|
import jwt
|
2020-09-16 15:41:02 +02:00
|
|
|
from fittrackee import bcrypt, db
|
2017-12-16 21:00:46 +01:00
|
|
|
from flask import current_app
|
2018-06-05 18:16:53 +02:00
|
|
|
from sqlalchemy import func
|
2020-05-02 18:00:17 +02:00
|
|
|
from sqlalchemy.ext.hybrid import hybrid_property
|
|
|
|
from sqlalchemy.sql.expression import select
|
2018-06-05 18:16:53 +02:00
|
|
|
|
|
|
|
from ..activities.models import Activity
|
2020-05-10 17:08:18 +02:00
|
|
|
from .utils_token import decode_user_token, get_user_token
|
2017-12-16 21:00:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
class User(db.Model):
|
|
|
|
__tablename__ = "users"
|
|
|
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
2018-01-01 16:59:46 +01:00
|
|
|
username = db.Column(db.String(20), unique=True, nullable=False)
|
2017-12-16 21:00:46 +01:00
|
|
|
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)
|
2017-12-17 09:16:08 +01:00
|
|
|
admin = db.Column(db.Boolean, default=False, nullable=False)
|
2018-01-01 16:59:46 +01:00
|
|
|
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)
|
2018-01-01 21:54:03 +01:00
|
|
|
picture = db.Column(db.String(255), nullable=True)
|
2018-06-11 15:10:18 +02:00
|
|
|
timezone = db.Column(db.String(50), nullable=True)
|
2019-08-31 16:33:46 +02:00
|
|
|
# does the week start Monday?
|
|
|
|
weekm = db.Column(db.Boolean(50), default=False, nullable=False)
|
2019-08-28 13:25:39 +02:00
|
|
|
activities = db.relationship(
|
2020-02-08 15:17:07 +01:00
|
|
|
'Activity', lazy=True, backref=db.backref('user', lazy='joined')
|
2019-08-28 13:25:39 +02:00
|
|
|
)
|
|
|
|
records = db.relationship(
|
2020-02-08 15:17:07 +01:00
|
|
|
'Record', lazy=True, backref=db.backref('user', lazy='joined')
|
2019-08-28 13:25:39 +02:00
|
|
|
)
|
2019-09-16 14:19:21 +02:00
|
|
|
language = db.Column(db.String(50), nullable=True)
|
2017-12-16 21:00:46 +01:00
|
|
|
|
|
|
|
def __repr__(self):
|
2018-05-23 17:30:22 +02:00
|
|
|
return f'<User {self.username!r}>'
|
2017-12-16 21:00:46 +01:00
|
|
|
|
|
|
|
def __init__(
|
2020-05-10 17:08:18 +02:00
|
|
|
self, username, email, password, created_at=datetime.utcnow()
|
2019-08-28 13:25:39 +02:00
|
|
|
):
|
2017-12-16 21:00:46 +01:00
|
|
|
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
|
|
|
|
|
2017-12-17 12:07:25 +01:00
|
|
|
@staticmethod
|
|
|
|
def encode_auth_token(user_id):
|
2018-01-01 16:59:46 +01:00
|
|
|
"""
|
|
|
|
Generates the auth token
|
|
|
|
:param user_id: -
|
|
|
|
:return: JWToken
|
|
|
|
"""
|
2017-12-16 21:00:46 +01:00
|
|
|
try:
|
2020-05-10 17:08:18 +02:00
|
|
|
return get_user_token(user_id)
|
|
|
|
except Exception as e:
|
|
|
|
return e
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def encode_password_reset_token(user_id):
|
|
|
|
"""
|
|
|
|
Generates the auth token
|
|
|
|
:param user_id: -
|
|
|
|
:return: JWToken
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
return get_user_token(user_id, password_reset=True)
|
2017-12-16 21:00:46 +01:00
|
|
|
except Exception as e:
|
|
|
|
return e
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def decode_auth_token(auth_token):
|
|
|
|
"""
|
|
|
|
Decodes the auth token
|
|
|
|
:param auth_token: -
|
|
|
|
:return: integer|string
|
|
|
|
"""
|
|
|
|
try:
|
2020-05-10 17:08:18 +02:00
|
|
|
return decode_user_token(auth_token)
|
2017-12-16 21:00:46 +01:00
|
|
|
except jwt.ExpiredSignatureError:
|
|
|
|
return 'Signature expired. Please log in again.'
|
|
|
|
except jwt.InvalidTokenError:
|
|
|
|
return 'Invalid token. Please log in again.'
|
2018-05-09 15:52:27 +02:00
|
|
|
|
2020-05-02 18:00:17 +02:00
|
|
|
@hybrid_property
|
|
|
|
def activities_count(self):
|
|
|
|
return Activity.query.filter(Activity.user_id == self.id).count()
|
|
|
|
|
|
|
|
@activities_count.expression
|
|
|
|
def activities_count(self):
|
|
|
|
return (
|
|
|
|
select([func.count(Activity.id)])
|
|
|
|
.where(Activity.user_id == self.id)
|
|
|
|
.label("activities_count")
|
|
|
|
)
|
|
|
|
|
2018-05-09 15:52:27 +02:00
|
|
|
def serialize(self):
|
2018-06-07 22:44:52 +02:00
|
|
|
sports = []
|
|
|
|
total = (None, None)
|
2020-05-02 18:00:17 +02:00
|
|
|
if self.activities_count > 0:
|
2019-08-28 13:25:39 +02:00
|
|
|
sports = (
|
2019-09-23 20:01:11 +02:00
|
|
|
db.session.query(Activity.sport_id)
|
2019-09-23 14:43:56 +02:00
|
|
|
.filter(Activity.user_id == self.id)
|
2019-08-28 13:25:39 +02:00
|
|
|
.group_by(Activity.sport_id)
|
2019-09-23 20:01:11 +02:00
|
|
|
.order_by(Activity.sport_id)
|
2019-08-28 13:25:39 +02:00
|
|
|
.all()
|
|
|
|
)
|
2019-09-23 14:43:56 +02:00
|
|
|
total = (
|
|
|
|
db.session.query(
|
|
|
|
func.sum(Activity.distance), func.sum(Activity.duration)
|
|
|
|
)
|
|
|
|
.filter(Activity.user_id == self.id)
|
|
|
|
.first()
|
|
|
|
)
|
2018-05-09 15:52:27 +02:00
|
|
|
return {
|
|
|
|
'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,
|
2018-06-05 18:16:53 +02:00
|
|
|
'picture': self.picture is not None,
|
2018-06-11 15:10:18 +02:00
|
|
|
'timezone': self.timezone,
|
2019-08-31 16:33:46 +02:00
|
|
|
'weekm': self.weekm,
|
2019-09-16 14:19:21 +02:00
|
|
|
'language': self.language,
|
2020-05-02 18:00:17 +02:00
|
|
|
'nb_activities': self.activities_count,
|
2018-06-05 18:16:53 +02:00
|
|
|
'nb_sports': len(sports),
|
2019-09-23 20:01:11 +02:00
|
|
|
'sports_list': [
|
|
|
|
sport for sportslist in sports for sport in sportslist
|
|
|
|
],
|
2018-06-05 18:16:53 +02:00
|
|
|
'total_distance': float(total[0]) if total[0] else 0,
|
|
|
|
'total_duration': str(total[1]) if total[1] else "0:00:00",
|
2018-05-09 15:52:27 +02:00
|
|
|
}
|