Workout With Friends
Stay fit with a little motivation
 All Classes Namespaces Files Functions Variables Properties
challenge.py
Go to the documentation of this file.
1 from __future__ import unicode_literals
2 from sqlalchemy.ext.declarative import declared_attr
3 from sqlalchemy.orm import backref, relationship
4 from sqlalchemy.schema import Column, ForeignKey
5 from sqlalchemy.types import DateTime, Integer, Numeric, SmallInteger
6 from wowf.lib.utils import current_timestamp
7 from wowf.models.lookup_tables import ChallengeType
8 from wowf.models.meta import Base
9 from wowf.models.pivot_tables import UserChallenge
10 
11 
12 ##
13 #
14 # Base class for ALL challenges.
15 #
16 class Challenge(Base):
17 
18  __tablename__ = 'challenges'
19  __mapper_args__ = {'polymorphic_on': 'challenge_type_id', 'with_polymorphic': '*'}
20  id = Column(Integer(unsigned=True), primary_key=True)
21  user_id = Column(Integer(unsigned=True), ForeignKey('users.id'), nullable=False)
22  challenge_type_id = Column(
23  Integer(unsigned=True), ForeignKey('challenge_types.id', ondelete='cascade'),
24  nullable=False)
25  created_at = Column(DateTime, nullable=False, default=current_timestamp)
26 
27  _creator = relationship('User', lazy='joined')
28  competitors = relationship(
29  'User', backref=backref('challenges', lazy='dynamic'),
30  secondary='users_challenges', lazy='dynamic')
31 
32  def _get_creator(self):
33  return self._creator
34 
35  ##
36  #
37  # Set the creator, and accept the challenge for him.
38  #
39  def _set_creator(self, creator):
40  self._creator = creator
41  pivot = UserChallenge.create(creator, self)
42  pivot.accept()
43 
44  creator = property(_get_creator, _set_creator)
45 
46  ##
47  #
48  # Add the user to the list of competitors.
49  #
50  def add_competitor(self, user):
51  if user not in self.competitors:
52  self.competitors.append(user)
53 
54  ##
55  #
56  # Remove the user from the list of competitors.
57  #
58  def remove_competitor(self, user):
59  if user in self.competitors:
60  self.competitors.remove(user)
61 
62  ##
63  #
64  # Check if the challenge requires the use of a heart rate device.
65  #
67  return isinstance(self, DeviceChallenge)
68 
69  ##
70  #
71  # Check if the challenge is a weight lifting challenge.
72  #
74  return isinstance(self, WeightChallenge)
75 
76  ##
77  #
78  # Check if the challenge is a speed challenge.
79  #
80  def is_speed_challenge(self):
81  return isinstance(self, SpeedChallenge)
82 
83  ##
84  #
85  # Check if the challenge is an endurance challenge.
86  #
88  return isinstance(self, EnduranceChallenge)
89 
90  ##
91  #
92  # Check if the challenge is a bench press challenge.
93  #
95  return isinstance(self, BenchPressChallenge)
96 
97  ##
98  #
99  # Check if the challenge is a squat challenge.
100  #
102  return isinstance(self, SquatChallenge)
103 
104  ##
105  #
106  # Check if both competitors have uploaded a workout.
107  #
108  def is_completed(self):
109  return self.workouts.count() == 2
110 
111  ##
112  #
113  # Check if given user is the winner of the challenge.
114  #
115  def user_is_winner(self, user):
116  if self.is_completed():
117  winning_workout = self.workouts.order_by(Workout.points.desc()).first()
118  return user is winning_workout.user
119 
120 ##
121 #
122 # Used for SQLAlchemys joined table inheritance (polymorphism).
123 #
124 class _Challenge(object):
125 
126  @declared_attr
127  def id(cls):
128  return Column(
129  Integer(unsigned=True), ForeignKey('challenges.id', ondelete='cascade'),
130  primary_key=True)
131 
132 
133 ##
134 #
135 # Base class for all challenges which require the use of a heart rate device.
136 #
138  pass
139 
140 
141 ##
142 #
143 # Base class for all weight related challenges.
144 #
145 class WeightChallenge(_Challenge):
146 
147  percentage = Column(Numeric(3, 2), nullable=False, doc='percentage of body weight')
148 
149  @classmethod
150  def create(cls, creator, percentage):
151  return super(WeightChallenge, cls).create(creator=creator, percentage=percentage)
152 
153  ##
154  #
155  # How much weight this user needs to lift for this competition.
156  #
157  def calculate_user_weight(self, user):
158  return round(self.percentage * user.weight, 2)
159 
160 
162 
163  __tablename__ = 'speed_challenges'
164  __mapper_args__ = {'polymorphic_identity': ChallengeType.lookup_data.index('speed') + 1}
165  distance = Column(SmallInteger(unsigned=True), nullable=False, doc='distance in meters')
166 
167  @property
168  def description(self):
169  return 'Sprint %d meters as fast as you can. The person with the fastest time wins.' % (
170  self.distance)
171 
172  def __unicode__(self):
173  return '%d meter speed challenge' % self.distance
174 
175  @classmethod
176  def create(cls, creator, distance):
177  return super(SpeedChallenge, cls).create(creator=creator, distance=distance)
178 
179 
181 
182  __tablename__ = 'endurance_challenges'
183  __mapper_args__ = {'polymorphic_identity': ChallengeType.lookup_data.index('endurance') + 1}
184  duration = Column(SmallInteger(unsigned=True), nullable=False, doc='duration in minutes')
185 
186  @property
187  def description(self):
188  return 'Run as hard as you can for %d minutes. The person with the highest vitals wins.' % (
189  self.duration)
190 
191  def __unicode__(self):
192  return '%d minute endurance challenge' % self.duration
193 
194  @classmethod
195  def create(cls, creator, duration):
196  return super(EnduranceChallenge, cls).create(creator=creator, duration=duration)
197 
198 
200 
201  __tablename__ = 'bench_press_challenges'
202  __mapper_args__ = {'polymorphic_identity': ChallengeType.lookup_data.index('bench_press') + 1}
203 
204  @property
205  def description(self):
206  return 'Bench press %d%% of your body weight for as many repetitions as you can. The person with the most repetitions wins.' % (
207  self.percentage * 100)
208 
209  def __unicode__(self):
210  return '%d%% bench press challenge' % (self.percentage * 100)
211 
212 
214 
215  __tablename__ = 'squat_challenges'
216  __mapper_args__ = {'polymorphic_identity': ChallengeType.lookup_data.index('squat') + 1}
217 
218  @property
219  def description(self):
220  return 'Squat %d%% of your body weight for as many repetitions as you can. The person with the most repetitions wins.' % (
221  self.percentage * 100)
222 
223  def __unicode__(self):
224  return '%d%% squat challenge' % (self.percentage * 100)
225 
226 
227 from wowf.models.workout import Workout
228