1 from __future__
import unicode_literals
4 from sqlalchemy.orm
import synonym
5 from sqlalchemy.schema
import Column
6 from sqlalchemy.sql
import and_, or_, func
7 from sqlalchemy.types
import (
8 Boolean, CHAR, Date, DateTime, Enum, Integer, Numeric,
13 from wowf.lib.utils import calculate_bmi, current_timestamp, years_ago
26 __tablename__ =
'users'
27 index_fields = [
'username']
28 id = Column(Integer(unsigned=
True), primary_key=
True)
29 username = Column(Unicode(10), nullable=
False, unique=
True)
30 email = Column(Unicode(254), nullable=
False, unique=
True)
31 _password = Column(
'password', CHAR(60), nullable=
False)
32 gender = Column(Enum(
'F',
'M', name=
'user_genders'), nullable=
False)
33 dob = Column(Date, nullable=
False)
34 weight = Column(Numeric(7, 4), nullable=
False, doc=
'weight in kilograms')
35 height = Column(Numeric(5, 4), nullable=
False, doc=
'height in meters')
36 timezone = Column(Unicode(50))
37 _avatar = Column(
'avatar', Unicode(40))
38 is_active = Column(Boolean, nullable=
False, default=
True)
39 created_at = Column(DateTime, nullable=
False, default=current_timestamp)
40 last_active_at = Column(DateTime, nullable=
False, default=current_timestamp)
53 password = synonym(
'_password', descriptor=property(_get_password, _set_password))
65 versions = settings.from_prefix(
'avatar_size_')
67 avatar = settings.avatar_default
68 return StoredImage(settings.avatar_dir, avatar, versions)
75 filename =
'%s%s' % (hashlib.md5(str(self.
id)).hexdigest(),
76 os.path.splitext(avatar.filename)[1])
77 versions = settings.from_prefix(
'avatar_size_')
81 avatar = synonym(
'_avatar', descriptor=property(_get_avatar, _set_avatar))
108 return 'under weight'
109 elif NORMAL[0] <= bmi <= NORMAL[1]:
110 return 'normal weight'
111 elif OVER[0] <= bmi <= OVER[1]:
122 points = (DBSession.query(func.sum(Workout.points))
123 .filter(Workout.user_id==self.
id)
125 return int(points
or 0)
127 def __init__(self, username, email, password, gender, dob, weight, height):
145 return cls.query.filter(cls.username==username).first()
153 return cls.query.filter(cls.email==email).first()
156 def create(cls, username, email, password, gender, dob, weight, height):
157 return super(User, cls).
create(
158 username=username, email=email, password=password, gender=gender,
159 dob=dob, weight=weight, height=height)
166 def search(cls, terms, limit=50, page=1):
167 pager =
Pager(page, limit)
168 return (cls._get_search_query(terms)
169 .order_by(cls.username.asc())
171 .offset(pager.offset)
176 return cls._get_search_query(terms).count()
191 def update_profile(self, username, email, gender, dob, weight, height, timezone):
219 speed = (DBSession.query(func.avg(SpeedWorkout.speed))
220 .outerjoin(SpeedChallenge, SpeedChallenge.id==SpeedWorkout.challenge_id)
221 .filter(SpeedChallenge.distance==distance)
222 .filter(SpeedWorkout.user_id==self.
id)
232 heart_rate = (DBSession.query(func.avg(EnduranceWorkout.heart_rate))
233 .outerjoin(EnduranceChallenge, EnduranceChallenge.id==EnduranceWorkout.challenge_id)
234 .filter(EnduranceChallenge.duration==duration)
235 .filter(EnduranceWorkout.user_id==self.
id)
245 calories_burned = (DBSession.query(func.avg(EnduranceWorkout.calories_burned))
246 .outerjoin(EnduranceChallenge, EnduranceChallenge.id==EnduranceWorkout.challenge_id)
247 .filter(EnduranceChallenge.duration==duration)
248 .filter(EnduranceWorkout.user_id==self.
id)
250 return calories_burned
258 repetitions = (DBSession.query(func.avg(BenchPressWorkout.repetitions))
259 .outerjoin(BenchPressChallenge, BenchPressChallenge.id==BenchPressWorkout.challenge_id)
260 .filter(BenchPressChallenge.percentage==percentage)
261 .filter(BenchPressWorkout.user_id==self.
id)
271 repetitions = (DBSession.query(func.avg(SquatWorkout.repetitions))
272 .outerjoin(SquatChallenge, SquatChallenge.id==SquatWorkout.challenge_id)
273 .filter(SquatChallenge.percentage==percentage)
274 .filter(SquatWorkout.user_id==self.
id)
283 return (DBSession.query(func.avg(SpeedWorkout.speed), SpeedWorkout.created_at)
284 .outerjoin(SpeedChallenge, SpeedChallenge.id==SpeedWorkout.challenge_id)
285 .filter(SpeedChallenge.distance==distance)
286 .filter(SpeedWorkout.user_id==self.
id)
287 .group_by(func.day(SpeedWorkout.created_at))
295 return (DBSession.query(func.avg(EnduranceWorkout.heart_rate), EnduranceWorkout.created_at)
296 .outerjoin(EnduranceChallenge, EnduranceChallenge.id==EnduranceWorkout.challenge_id)
297 .filter(EnduranceChallenge.duration==duration)
298 .filter(EnduranceWorkout.user_id==self.
id)
299 .group_by(func.day(EnduranceWorkout.created_at))
307 return (DBSession.query(func.avg(EnduranceWorkout.calories_burned), EnduranceWorkout.created_at)
308 .outerjoin(EnduranceChallenge, EnduranceChallenge.id==EnduranceWorkout.challenge_id)
309 .filter(EnduranceChallenge.duration==duration)
310 .filter(EnduranceWorkout.user_id==self.
id)
311 .group_by(func.day(EnduranceWorkout.created_at))
319 return (DBSession.query(func.avg(BenchPressWorkout.repetitions), BenchPressWorkout.created_at)
320 .outerjoin(BenchPressChallenge, BenchPressChallenge.id==BenchPressWorkout.challenge_id)
321 .filter(BenchPressChallenge.percentage==percentage)
322 .filter(BenchPressWorkout.user_id==self.
id)
323 .group_by(func.day(BenchPressWorkout.created_at))
331 return (DBSession.query(func.avg(SquatWorkout.repetitions), SquatWorkout.created_at)
332 .outerjoin(SquatChallenge, SquatChallenge.id==SquatWorkout.challenge_id)
333 .filter(SquatChallenge.percentage==percentage)
334 .filter(SquatWorkout.user_id==self.
id)
335 .group_by(func.day(BenchPressWorkout.created_at))
343 pager =
Pager(page, limit)
345 .order_by(User.username.asc())
347 .offset(pager.offset)
371 Buddy.create(user_id=self.
id, buddy_id=user.id)
372 notification = NewBuddyNotification.create(user=self)
373 notification.add_recipients([user])
389 pager =
Pager(page, limit)
390 return (self.challenges
391 .order_by(Challenge.created_at.desc())
393 .offset(pager.offset)
401 return (Workout.query
402 .filter(Workout.user_id==self.
id, Workout.challenge_id==challenge.id)
410 return self.challenges.count()
413 challenge = SpeedChallenge.create(self, distance)
417 challenge = EnduranceChallenge.create(self, duration)
421 challenge = BenchPressChallenge.create(self, percentage)
425 challenge = SquatChallenge.create(self, percentage)
429 workout = SpeedWorkout.create(self, challenge, samples)
433 workout = EnduranceWorkout.create(self, challenge, samples)
437 workout = BenchPressWorkout.create(self, challenge, repetitions)
441 workout = SquatWorkout.create(self, challenge, repetitions)
449 return challenge
in self.challenges
456 return self
is challenge.creator
464 return pivot.is_accepted
is True
472 return pivot.is_accepted
is False
482 notification = AcceptedChallengeNotification.create(user=self, challenge=challenge)
483 notification.add_recipients(set(challenge.competitors) - set([self]))
493 notification = DeniedChallengeNotification.create(user=self, challenge=challenge)
494 notification.add_recipients(set(challenge.competitors) - set([self]))
501 pager =
Pager(page, limit)
504 .offset(pager.offset)
519 pager =
Pager(page, limit)
522 .offset(pager.offset)
537 unconfirmed_notifications = (
538 UserNotification.query.filter(UserNotification.user_id==self.
id))
539 for notification
in unconfirmed_notifications:
540 notification.confirm()
551 return cls._get_fulltext_query(terms)
558 challenge.add_competitor(competitor)
559 notification = RequestedChallengeNotification.create(user=self, challenge=challenge)
560 notification.add_recipients([competitor])
568 notification = UploadedWorkoutNotification.create(user=self, challenge=workout.challenge)
569 notification.add_recipients(set(workout.challenge.competitors) - set([self]))
578 .outerjoin(Buddy, Buddy.user_id==User.id)
579 .filter(Buddy.buddy_id==self.
id))
580 buddies = (User.query
581 .outerjoin(Buddy, Buddy.buddy_id==User.id)
582 .filter(Buddy.user_id==self.
id))
583 return users.union(buddies)
592 and_(Buddy.user_id==self.
id,
593 Buddy.buddy_id==user.id),
594 and_(Buddy.buddy_id==self.
id,
595 Buddy.user_id==user.id)))
603 return (UserChallenge.query
604 .filter(UserChallenge.user_id==self.
id, UserChallenge.challenge_id==challenge.id)
612 notifications = (Notification.query
613 .outerjoin(UserNotification,
614 UserNotification.notification_id==Notification.id)
615 .filter(UserNotification.user_id==self.
id)
616 .order_by(Notification.created_at.desc()))
618 notifications = notifications.filter(UserNotification.is_confirmed==
False)
624 BenchPressChallenge, Challenge, EnduranceChallenge,
625 SpeedChallenge, SquatChallenge)
627 AcceptedChallengeNotification, DeniedChallengeNotification,
628 NewBuddyNotification, Notification, RequestedChallengeNotification,
629 UploadedWorkoutNotification)
632 BenchPressWorkout, EnduranceWorkout, SpeedWorkout,
633 SquatWorkout, Workout)