From 779a07c96ba8f6a7873419998611f5ae6fc87a9f Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 14 Nov 2018 09:50:38 +0100 Subject: [PATCH 1/3] duplicates concept --- rowers/.#models.py | 1 + rowers/dataprep.py | 30 ++++++++++++++++++++++++------ rowers/models.py | 3 ++- rowers/views.py | 6 ++++++ 4 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 rowers/.#models.py diff --git a/rowers/.#models.py b/rowers/.#models.py new file mode 100644 index 00000000..11d1b7d9 --- /dev/null +++ b/rowers/.#models.py @@ -0,0 +1 @@ +E408191@CZ27LT9RCGN72.21348:1542056188 \ No newline at end of file diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 7d12f7f7..2b023b68 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -999,13 +999,30 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', maxhr = np.nan_to_num(maxhr) averagehr = np.nan_to_num(averagehr) + duplicate = True + + t = datetime.datetime.strptime(duration,"%H:%M:%S.%f") + delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second) + + workoutenddatetime = workoutstartdatetime+delta + # check for duplicate start times and duration - ws = Workout.objects.filter(startdatetime=workoutstartdatetime, - distance=totaldist, - user=r) - if (len(ws) != 0): - message = "Warning: This workout probably already exists in the database" - privacy = 'hidden' + ws = Workout.objects.filter(user=r,date=workoutdate).exclude( + startdatetime__gt=workoutenddatetime + ) + + ws2 = [] + + for ww in ws: + t = ww.duration + delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second) + enddatetime = ww.startdatetime+delta + if enddatetime > workoutstartdatetime: + ws2.append(ww) + + if (len(ws2) != 0): + message = "Warning: This workout overlaps with an existing one and was marked as a duplicate" + duplicate = True w = Workout(user=r, name=title, date=workoutdate, @@ -1014,6 +1031,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', duration=duration, distance=totaldist, weightcategory=r.weightcategory, starttime=workoutstarttime, + duplicate=duplicate, workoutsource=workoutsource, rankingpiece=rankingpiece, forceunit=forceunit, diff --git a/rowers/models.py b/rowers/models.py index f628078f..008f8329 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2134,6 +2134,7 @@ class Workout(models.Model): privacy = models.CharField(default='visible',max_length=30, choices=privacychoices) rankingpiece = models.BooleanField(default=False,verbose_name='Ranking Piece') + duplicate = models.BooleanField(default=False,verbose_name='Duplicate Workout') def __unicode__(self): @@ -2404,7 +2405,7 @@ class WorkoutForm(ModelForm): # duration = forms.TimeInput(format='%H:%M:%S.%f') class Meta: model = Workout - fields = ['name','date','starttime','timezone','duration','distance','workouttype','boattype','weightcategory','notes','rankingpiece'] + fields = ['name','date','starttime','timezone','duration','distance','workouttype','boattype','weightcategory','notes','rankingpiece','duplicate'] widgets = { 'date': AdminDateWidget(), 'notes': forms.Textarea, diff --git a/rowers/views.py b/rowers/views.py index 283703fc..18461b6f 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -3380,6 +3380,11 @@ def addmanual_view(request): rankingpiece = form.cleaned_data['rankingpiece'] except KeyError: rankingpiece = False + + try: + duplicate = form.cleaned_data['duplicate'] + except KeyError: + duplicate = False if private: privacy = 'private' @@ -3403,6 +3408,7 @@ def addmanual_view(request): avghr=avghr, rankingpiece=rankingpiece, avgpwr=avgpwr, + duplicate=duplicate, avgspm=avgspm, title = name, notes=notes, From 840e0b55f38d9965d6eb3d8746fa55b106958ebf Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 14 Nov 2018 10:26:40 +0100 Subject: [PATCH 2/3] review duplicates upon delete workout --- rowers/.#models.py | 1 - rowers/dataprep.py | 7 ++++--- rowers/models.py | 37 ++++++++++++++++++++++++++++++++++++- rowers/views.py | 6 ++++++ 4 files changed, 46 insertions(+), 5 deletions(-) delete mode 100644 rowers/.#models.py diff --git a/rowers/.#models.py b/rowers/.#models.py deleted file mode 100644 index 11d1b7d9..00000000 --- a/rowers/.#models.py +++ /dev/null @@ -1 +0,0 @@ -E408191@CZ27LT9RCGN72.21348:1542056188 \ No newline at end of file diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 2b023b68..183ffcb9 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -999,7 +999,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', maxhr = np.nan_to_num(maxhr) averagehr = np.nan_to_num(averagehr) - duplicate = True + duplicate = False t = datetime.datetime.strptime(duration,"%H:%M:%S.%f") delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second) @@ -1007,7 +1007,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', workoutenddatetime = workoutstartdatetime+delta # check for duplicate start times and duration - ws = Workout.objects.filter(user=r,date=workoutdate).exclude( + ws = Workout.objects.filter(user=r,date=workoutdate,duplicate=False).exclude( startdatetime__gt=workoutenddatetime ) @@ -1019,7 +1019,8 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', enddatetime = ww.startdatetime+delta if enddatetime > workoutstartdatetime: ws2.append(ww) - + + if (len(ws2) != 0): message = "Warning: This workout overlaps with an existing one and was marked as a duplicate" duplicate = True diff --git a/rowers/models.py b/rowers/models.py index 008f8329..dfa1726a 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2182,7 +2182,42 @@ def auto_delete_file_on_delete(sender, instance, **kwargs): if instance.csvfilename+'.gz': if os.path.isfile(instance.csvfilename+'.gz'): os.remove(instance.csvfilename+'.gz') - + +@receiver(models.signals.post_delete,sender=Workout) +def update_duplicates_on_delete(sender, instance, **kwargs): + if instance.id: + + duplicates = Workout.objects.filter( + user=instance.user,date=instance.date, + duplicate=True) + + for d in duplicates: + t = d.duration + delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second) + workoutenddatetime = d.startdatetime+delta + ws = Workout.objects.filter( + user=d.user,date=d.date, + ).exclude( + pk__in=[instance.pk,d.pk] + ).exclude( + startdatetime__gt=workoutenddatetime + ) + + + ws2 = [] + + for ww in ws: + t = ww.duration + delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second) + enddatetime = ww.startdatetime+delta + if enddatetime > d.startdatetime: + ws2.append(ww) + + if len(ws2) == 0: + d.duplicate=False + d.save() + + # Delete stroke data from the database when a workout is deleted @receiver(models.signals.post_delete,sender=Workout) def auto_delete_strokedata_on_delete(sender, instance, **kwargs): diff --git a/rowers/views.py b/rowers/views.py index 18461b6f..7ffbb025 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -9859,6 +9859,11 @@ def workout_edit_view(request,id=0,message="",successmessage=""): except KeyError: rankingpiece =- Workout.objects.get(id=id).rankingpiece + try: + duplicate = form.cleaned_data['duplicate'] + except KeyError: + duplicate = Workout.objects.get(id=id).duplicate + if private: privacy = 'private' else: @@ -9898,6 +9903,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): row.duration = duration row.distance = distance row.boattype = boattype + row.duplicate = duplicate row.privacy = privacy row.rankingpiece = rankingpiece row.timezone = thetimezone From db2f31ff5bfe40fd9ac024c0b00ca2d070eac579 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 14 Nov 2018 10:56:42 +0100 Subject: [PATCH 3/3] activity chart without duplicates --- rowers/interactiveplots.py | 7 ++++--- rowers/views.py | 22 ++++++++++++++++++++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 5d61220e..c08ef90d 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -237,8 +237,6 @@ def interactive_boxchart(datadf,fieldname,extratitle=''): def interactive_activitychart(workouts,startdate,enddate,stack='type'): - if len(workouts) == 0: - return "","" dates = [] dates_sorting = [] @@ -316,7 +314,10 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'): label = CatAttr(columns=['date'], sort=False), xlabel='Date', ylabel='Time', - title='Activity', + title='Activity {d1} to {d2}'.format( + d1 = startdate.strftime("%Y-%m-%d"), + d2 = enddate.strftime("%Y-%m-%d"), + ), stack=stack, plot_width=350, plot_height=250, diff --git a/rowers/views.py b/rowers/views.py index 7ffbb025..e5997a68 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -6754,6 +6754,7 @@ def workouts_view(request,message='',successmessage='', enddate = startdate startdate = s + startdatestring = startdate.strftime('%Y-%m-%d') enddatestring = enddate.strftime('%Y-%m-%d') @@ -6769,6 +6770,10 @@ def workouts_view(request,message='',successmessage='', except ValueError: activity_enddate = enddate + g_startdate = activity_startdate + g_enddate = activity_enddate + + if teamid: try: theteam = Team.objects.get(id=teamid) @@ -6785,6 +6790,7 @@ def workouts_view(request,message='',successmessage='', team=theteam, startdatetime__gte=activity_startdate, startdatetime__lte=activity_enddate, + duplicate=False, privacy='visible').order_by("-date", "-starttime") elif theteam.viewing == 'coachonly': workouts = Workout.objects.filter( @@ -6796,6 +6802,7 @@ def workouts_view(request,message='',successmessage='', team=theteam,user=r, startdatetime__gte=activity_startdate, enddatetime__lte=activity_enddate, + duplicate=False, privacy='visible').order_by("-startdatetime") @@ -6811,6 +6818,7 @@ def workouts_view(request,message='',successmessage='', user=r, startdatetime__gte=activity_startdate, startdatetime__lte=activity_enddate, + duplicate=False, privacy='visible').order_by("-startdatetime") else: theteam = None @@ -6820,9 +6828,18 @@ def workouts_view(request,message='',successmessage='', startdatetime__lte=enddate).order_by("-date", "-starttime") g_workouts = Workout.objects.filter( user=r, + duplicate=False, startdatetime__gte=activity_startdate, startdatetime__lte=activity_enddate).order_by("-startdatetime") + + if len(g_workouts) == 0: + g_workouts = Workout.objects.filter( + user=r, + startdatetime__gte=timezone.now()-timedelta(days=15)).order_by("-startdatetime") + g_enddate = timezone.now() + g_startdate = (timezone.now()-timedelta(days=15)) + if rankingonly: workouts = workouts.exclude(rankingpiece=False) @@ -6860,9 +6877,10 @@ def workouts_view(request,message='',successmessage='', else: stack='type' + script,div = interactive_activitychart(g_workouts, - activity_startdate, - activity_enddate, + g_startdate, + g_enddate, stack=stack) messages.info(request,successmessage)