def setUp(self): self.central = pytz.timezone('US/Central') self.now = datetime.datetime.now(tz=self.central) self.race = Race(race_name='Test Race', race_type=Race.RACE_TYPE_FINALS, race_start_time=self.now) self.race.save() self.race_control = RaceControl(current_race=self.race) self.race_control.save() self.pick_checkpoint = Checkpoint(checkpoint_number=1, checkpoint_name="Test Checkpoint 1") self.pick_checkpoint.save() self.drop_checkpoint = Checkpoint(checkpoint_number=2, checkpoint_name="Test Checkpoint 2") self.drop_checkpoint.save() self.other_checkpoint = Checkpoint(checkpoint_number=3, checkpoint_name="Test Checkpoint 3") self.other_checkpoint.save() self.ready_now_job = Job(job_id=1, race=self.race, pick_checkpoint=self.pick_checkpoint, drop_checkpoint=self.drop_checkpoint, minutes_ready_after_start=0) self.ready_now_job.save() self.racer = Racer(racer_number=320, first_name='Doug', last_name='Suriano', category=Racer.RACER_CATEGORY_MESSENGER) self.racer.save() self.raceentry = RaceEntry(racer=self.racer, race=self.race) self.raceentry.save() self.run = Run(pk=1, job=self.ready_now_job, race_entry=self.raceentry, status=Run.RUN_STATUS_PICKED, utc_time_picked=datetime.datetime.now(tz=pytz.utc)) self.run.save()
def index(request): #user = User.get_by_key_name("key_"+self.cleaned_data['username'].lower()) username = request.user.username user = User.get_by_key_name("key_"+username.lower()) if user and user.is_active: last_scrape = user.nike_last_scrape else: last_scrape = None return object_list(request, Run.all().filter('user ='******'-run_time'), extra_context={'last_scrape':last_scrape})
class DropTestCase(APITestCase): def setUp(self): self.central = pytz.timezone('US/Central') self.now = datetime.datetime.now(tz=self.central) self.race = Race(race_name='Test Race', race_type=Race.RACE_TYPE_FINALS, race_start_time=self.now) self.race.save() self.race_control = RaceControl(current_race=self.race) self.race_control.save() self.pick_checkpoint = Checkpoint(checkpoint_number=1, checkpoint_name="Test Checkpoint 1") self.pick_checkpoint.save() self.drop_checkpoint = Checkpoint(checkpoint_number=2, checkpoint_name="Test Checkpoint 2") self.drop_checkpoint.save() self.other_checkpoint = Checkpoint(checkpoint_number=3, checkpoint_name="Test Checkpoint 3") self.other_checkpoint.save() self.ready_now_job = Job(job_id=1, race=self.race, pick_checkpoint=self.pick_checkpoint, drop_checkpoint=self.drop_checkpoint, minutes_ready_after_start=0) self.ready_now_job.save() self.racer = Racer(racer_number=320, first_name='Doug', last_name='Suriano', category=Racer.RACER_CATEGORY_MESSENGER) self.racer.save() self.raceentry = RaceEntry(racer=self.racer, race=self.race) self.raceentry.save() self.run = Run(pk=1, job=self.ready_now_job, race_entry=self.raceentry, status=Run.RUN_STATUS_PICKED, utc_time_picked=datetime.datetime.now(tz=pytz.utc)) self.run.save() def test_not_matching_confirm_code_with_racer(self): data = {'racer_number' : 999, 'checkpoint': 2, 'confirm_code' : 1 } response = self.client.post('/api/v1/drop/', data, format='json') self.assertEqual(response.data, {'error' : True, 'error_title' : 'Wrong Racer #', 'error_description' : 'Racer # 999 does not a drop off with confirm code 1.'}) def test_incorrect_confirm_code(self): data = {'racer_number' : 320, 'checkpoint': 2, 'confirm_code' : 99 } response = self.client.post('/api/v1/drop/', data, format='json') self.assertEqual(response.data, {'error' : True, 'error_title' : 'Cannot Find Confirm Code', 'error_description' : "No job's' drop off assoicated with confirm code 99."}) def test_wrong_checkpint(self): data = {'racer_number' : 320, 'checkpoint': 6, 'confirm_code' : 1 } response = self.client.post('/api/v1/drop/', data, format='json') self.assertEqual(response.data, {'error' : True, 'error_title' : 'Wrong Checkpoint', 'error_description' : 'This drop off needs to be made at Test Checkpoint 2.'}) def test_racer_already_dropped_off(self): data = {'racer_number' : 320, 'checkpoint': 2, 'confirm_code' : 1 } response = self.client.post('/api/v1/drop/', data, format='json') drop_time = datetime.datetime.now(tz=self.central).strftime('%I:%M %p') response = self.client.post('/api/v1/drop/', data, format='json') self.assertEqual(response.data, {'error' : True, 'error_title' : 'Job already dropped off', 'error_description' : 'The run was already dropped off at {}.'.format(drop_time)}) def test_ok_drop(self): data = {'racer_number' : 320, 'checkpoint': 2, 'confirm_code' : 1 } response = self.client.post('/api/v1/drop/', data, format='json') self.assertEqual(response.data, {'error' : False, 'error_title' : None, 'error_description' : None})
def get_nike_plus_data(request): # TODO: protect against the case where a user_id hasn't been set. force this to be set upon registration? # TODO: Only set new last_scrape_time if the scrape is successful username = request.user.username user = User.get_by_key_name("key_"+username.lower()) if user and user.is_active: last_scrape_time = user.nike_last_scrape userId = user.nike_user_id else: last_scrape_time = None if not last_scrape_time: last_scrape_time = datetime.datetime(1970, 1, 1) # Set it to an arbitrary early date #response = urllib2.urlopen('http://nikeplus.nike.com/nikeplus/v1/services/widget/get_public_run_list.jsp?userID=%s' % userId).read() #response = urlfetch.fetch('https://secure-nikerunning.nike.com/nikeplus/v1/services/app/run_list.jsp') #response = urlfetch.fetch('http://nikerunning.nike.com/nikeplus/v2/services/app/run_list.jsp?userID=%s&startIndex=0&endIndex=5' % userId) # don't specify startIndex and endIndex in the URL i.e. get all runs response = urlfetch.fetch('http://nikerunning.nike.com/nikeplus/v2/services/app/run_list.jsp?userID=%s' % userId) import logging logging.debug(response.content) dom = minidom.parseString(response.content) run_ids_and_times = [] # N.B. in the following code I replaced 'startTime' with 'syncTime' - this makes sense # AUG 14TH 2010 - NOTE - THIS IS PROBABLY REALLY INEFFICIENT!!! # WOULD BE BETTER TO LIMIT THE AMOUNT OF RUNS I GET IN THE REQUEST (i.e. use startIndex/endIndex) # THIS LIMIT NEEDS TO BE BASED ON nike_last_scrape # # IDEA: START AT END OF XML FILE AND MOVE BACKWARDS, CHECKING THE syncTime value until # it becomes earlier than nike_last_scrape for run in dom.getElementsByTagName('run'): run_id = run.getAttribute('id') sync_time = run.getElementsByTagName('syncTime')[0] sync_time = sync_time.toxml() sync_time = sync_time.replace('<syncTime>', '') # Get rid of the opening syncTime tag sync_time = sync_time.split('+')[0] # Strip off the time zone stuff and closing tag sync_time = datetime.datetime.strptime(sync_time, '%Y-%m-%dT%H:%M:%S') run_ids_and_times.append((run_id, sync_time)) ##run = Run(run_id=run_id, run_time=run_time) ##run.put() # Only keep the runs which have been synced after the last_scrape_time run_ids_and_times = [(run_id, t) for (run_id, t) in run_ids_and_times if t > last_scrape_time] # Set last scrape time to now # TODO - uncomment the following line #user.nike_last_scrape = datetime.datetime.now() user.put() # No new runs so just return # TODO: Give the user some feedback e.g. a message saying 'No new runs' if len(run_ids_and_times) == 0: return HttpResponseRedirect('/runs/') cookie = Cookie.SimpleCookie() cookie.load(response.headers.get('set-cookie', '')) cookie['plusid'] = user.nike_user_id +"&nikerunning.nike.com" headers = { 'Host' : 'runlogger.appspot.com', 'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)', 'Cookie' : _makeCookieHeader(cookie) } # Save the new run(s) for run in dom.getElementsByTagName('run'): for (run_id, t) in run_ids_and_times: if run.getAttribute('id') == run_id: # Get the time the run started run_time = run.getElementsByTagName('startTime')[0] run_time = run_time.toxml() run_time = run_time.replace('<startTime>', '') # Get rid of the opening startTime tag run_time = run_time.split('+')[0] # Strip off the time zone stuff and closing tag run_time = datetime.datetime.strptime(run_time, '%Y-%m-%dT%H:%M:%S') distance = run.getElementsByTagName('distance')[0] distance = distance.toxml() distance = distance.replace('<distance>', '') distance = distance.replace('</distance>', '') dist_len = len('%.2f' % float(distance)) # Length of distance string when truncated to 2 D.P. distance = float(distance[:dist_len]) duration = run.getElementsByTagName('duration')[0] duration = duration.toxml() duration = duration.replace('<duration>', '') duration = duration.replace('</duration>', '') # TODO - TEST OUT THIS CODE WITH RUNS OVER AN HOUR LONG - WILL IT WORK? duration = float(duration)/1000/60 # Convert duration in ms to minutes decimal_part_of_mins, mins = math.modf(duration) gt_1hour = False if mins >= 60: gt_1hour = True mins_when_duration_gt_1hour, hours = math.modf(mins/60) mins = mins_when_duration_gt_1hour * 60 secs = decimal_part_of_mins * 60 if gt_1hour: duration_pretty = '%s:%s:%02d' % (int(hours), int(round(mins)), int(round(secs))) else: duration_pretty = '%s:%02d' % (int(mins), int(round(secs))) # Get GPX data # TODO - don't hardcode the run ID! response = urlfetch.fetch('https://secure-nikerunning.nike.com/nikeplus/v2/services/app/get_gps_detail.jsp?_plus=true&id=%s&format=json' % run_id, headers=headers) logging.debug('gpx data is:') logging.debug(response.content) new_run = Run(user=user, run_id=run_id, run_time=run_time, distance=distance, duration=duration, duration_pretty=duration_pretty, gpx_data=unicode(response.content)) new_run.put() return HttpResponseRedirect('/runs/')
def detail(request, key): # isn't there a better way to do this? # e.g. by doing p = Poll.get_by_key_name(key) - didn't seem to work for me p = db.get(key) return object_detail(request, Run.all(), key)