diff --git a/rowers/integrations/c2.py b/rowers/integrations/c2.py index c718a887..14d522f1 100644 --- a/rowers/integrations/c2.py +++ b/rowers/integrations/c2.py @@ -1,5 +1,7 @@ from .integrations import SyncIntegration, NoTokenError -from rowers.models import User, Rower, Workout, TombStone +from rowers.models import User, Rower, Workout, TombStone, SyncRecord +from django.db.utils import IntegrityError + from rowingdata import rowingdata import numpy as np import datetime @@ -358,6 +360,16 @@ class C2Integration(SyncIntegration): def get_workout(self, id, *args, **kwargs): _ = self.open() + + record = SyncRecord( + rower = self.rower, + c2id = id, + ) + try: + record.save() + except IntegrityError: + return 0 + _ = myqueue(queuehigh, handle_c2_getworkout, self.user.id, @@ -413,21 +425,11 @@ class C2Integration(SyncIntegration): workouts = [] c2ids = [item['id'] for item in res.json()['data']] - knownc2ids = uniqify([ - w.uploadedtoc2 for w in Workout.objects.filter(user=self.rower) - ]) - tombstones = [ - t.uploadedtoc2 for t in TombStone.objects.filter(user=self.rower) - ] - parkedids = [] - try: - with open('c2blocked.json', 'r') as c2blocked: - jsondata = json.load(c2blocked) - parkedids = jsondata['ids'] - except: # pragma: no cover - pass - knownc2ids = uniqify(knownc2ids+tombstones+parkedids) + knownc2ids = uniqify([ + record.c2id for record in SyncRecord.objects.filter(rower=r) + ]) + for item in res.json()['data']: d = item['distance'] i = item['id'] diff --git a/rowers/integrations/nk.py b/rowers/integrations/nk.py index 466370b3..10393267 100644 --- a/rowers/integrations/nk.py +++ b/rowers/integrations/nk.py @@ -1,5 +1,6 @@ from .integrations import SyncIntegration, NoTokenError -from rowers.models import User, Rower, Workout, TombStone +from rowers.models import User, Rower, Workout, TombStone, SyncRecord +from django.db.utils import IntegrityError from rowers import mytypes from rowers.nkimportutils import * @@ -88,6 +89,15 @@ class NKIntegration(SyncIntegration): _ = self.open() r = self.rower + record = SyncRecord( + rower = r, + nkid = id, + ) + try: + record.save() + except IntegrityError: + return 0 + before = kwargs.get('before',0) after = kwargs.get('after',0) if not before: @@ -181,25 +191,8 @@ class NKIntegration(SyncIntegration): # get NK IDs nkids = [item['id'] for item in jsondata] knownnkids = uniqify([ - w.uploadedtonk for w in Workout.objects.filter(user=r) + record.nkid for record in SyncRecord.objects.filter(rower=r) ]) - tombstones = [ - t.uploadedtonk for t in TombStone.objects.filter(user=r) - ] - parkedids = [] - try: - with open('nkblocked.json', 'r') as nkblocked: - try: - jsondatal = json.load(nkblocked) - except: - jsondatal = { - 'ids':[] - } - parkedids = jsondatal['ids'] - except FileNotFoundError: # pragma: no cover - pass - - knownnkids = uniqify(knownnkids+tombstones+parkedids) workouts = [] diff --git a/rowers/management/commands/getsyncids.py b/rowers/management/commands/getsyncids.py new file mode 100644 index 00000000..422f1f23 --- /dev/null +++ b/rowers/management/commands/getsyncids.py @@ -0,0 +1,63 @@ +from django.core.management.base import BaseCommand +from rowers.models import Workout, TombStone, SyncRecord +from django.utils import timezone +from django.db.utils import IntegrityError + +class Command(BaseCommand): + def handle(self, *args, **options): + ws = Workout.objects.all() + aantal = ws.count() + counter = 0 + print('----- Workouts ---------') + for w in ws: + record = SyncRecord( + workout = w, + ) + if w.uploadedtostrava: + record.stravaid = w.uploadedtostrava + if w.uploadedtotp: + record.tpid = w.uploadedtotp + if w.uploadedtonk: + record.nkid = w.uploadedtonk + if w.uploadedtosporttracks: + record.sporttracksid = w.uploadedtosporttracks + if w.uploadedtoc2: + record.c2id = w.uploadedtoc2 + + try: + record.save() + except IntegrityError: + pass + + counter += 1 + if counter % 10 == 0: + print(counter,'/',aantal) + + print('----- Tombstones -------') + ts = TombStone.objects.all() + aantal = ts.count() + counter = 0 + for w in ts: + record = SyncRecord( + ) + if w.uploadedtostrava: + record.stravaid = w.uploadedtostrava + if w.uploadedtotp: + record.tpid = w.uploadedtotp + if w.uploadedtonk: + record.nkid = w.uploadedtonk + if w.uploadedtosporttracks: + record.sporttracksid = w.uploadedtosporttracks + if w.uploadedtoc2: + record.c2id = w.uploadedtoc2 + + try: + record.save() + except IntegrityError: + pass + + counter += 1 + if counter % 10 == 0: + print(counter,'/',aantal) + + diff --git a/rowers/models.py b/rowers/models.py index 770acd9e..98a9c73b 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -3447,6 +3447,7 @@ rpechoices = ( (10, '10 Max Effort (You can barely remember your name, you would rather rip out your toenails than go through this)') ) + class Workout(models.Model): workouttypes = mytypes.workouttypes workoutsources = mytypes.workoutsources @@ -3608,7 +3609,6 @@ class TombStone(models.Model): uploadedtotp = models.BigIntegerField(default=0) uploadedtonk = models.BigIntegerField(default=0) - @receiver(models.signals.pre_delete, sender=Workout) def create_tombstone_on_delete(sender, instance, **kwargs): t = TombStone( @@ -3623,6 +3623,23 @@ def create_tombstone_on_delete(sender, instance, **kwargs): # delete files belonging to workout instance # related GraphImage objects should be deleted automatically +class SyncRecord(models.Model): + workout = models.ForeignKey(Workout, on_delete=models.CASCADE, null=True) + rower = models.ForeignKey(Rower, on_delete=models.CASCADE, null=True) + stravaid = models.BigIntegerField(unique=True,null=True,default=None) + sporttracksid = models.BigIntegerField(unique=True,null=True,default=None) + nkid = models.BigIntegerField(unique=True,null=True,default=None) + c2id = models.BigIntegerField(unique=True,null=True,default=None) + tpid = models.BigIntegerField(unique=True,null=True,default=None) + + def save(self, *args, **kwargs): + if self.workout: + self.rower = self.workout.user + return super(SyncRecord, self).save(*args, **kwargs) + + + + @receiver(models.signals.post_delete, sender=Workout) def auto_delete_file_on_delete(sender, instance, **kwargs): diff --git a/rowers/tasks.py b/rowers/tasks.py index 857e844c..6a78d09f 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -15,7 +15,7 @@ application = get_wsgi_application() from rowers.models import ( Workout, GeoPolygon, GeoPoint, GeoCourse, VirtualRaceResult, CourseTestResult, Rower, - GraphImage, + GraphImage, SyncRecord ) import math @@ -84,6 +84,7 @@ import rowers.rowing_workout_metrics_pb2 as metrics_pb2 import rowers.rowing_workout_metrics_pb2_grpc as metrics_pb2_grpc from django.conf import settings +from django.db.utils import IntegrityError # extra read of config @@ -522,6 +523,9 @@ def handle_c2_sync(workoutid, url, headers, data, debug=False, **kwargs): workout.uploadedtoc2 = c2id workout.save() + record = SyncRecord(workout=workout,c2id=c2id) + record.save() + return 1 def splitstdata(lijst): @@ -3402,24 +3406,20 @@ def handle_nk_async_workout(alldata, userid, nktoken, nkid, delaysec, defaulttim # dologging('nklog.log','NK Workout ID {id}'.format(id=workoutid)) workout = Workout.objects.get(id=workoutid) newnkid = workout.uploadedtonk + sr = SyncRecord.objects.filter(nkid=newnkid) + if len(sr): + sr[0].workout = workout + try: + sr[0].save() + except IntegrityError: + pass + else: + sr = SyncRecord(workout=workout,nkid=newnkid) + try: + sr.save() + except IntegrityError: + pass - parkedids = [] - try: - with open('nkblocked.json', 'r') as nkblocked: - jsondata = json.load(nkblocked) - parkedids = jsondata['ids'] - except FileNotFoundError: # pragma: no cover - pass - - newparkedids = [id for id in parkedids if id != newnkid] - with open('nkblocked.json', 'wt') as nkblocked: - tdata = {'ids': newparkedids} - nkblocked.seek(0) - json.dump(tdata, nkblocked) - - # evt update workout summary - - # return return workoutid @@ -3693,20 +3693,8 @@ def handle_c2_async_workout(alldata, userid, c2token, c2id, delaysec, workout = Workout.objects.get(id=workoutid) newc2id = workout.uploadedtoc2 - parkedids = [] - with open('c2blocked.json', 'a+') as c2blocked: - try: - jsondata = json.load(c2blocked) - parkedids = jsondata['ids'] - except JSONDecodeError: # pragma: no cover - parkedids = [] - + record = SyncRecord(workout=workout,c2id=newc2id) - newparkedids = [id for id in parkedids if id != newc2id] - with open('c2blocked.json', 'wt') as c2blocked: - tdata = {'ids': newparkedids} - c2blocked.seek(0) - json.dump(tdata, c2blocked) # set distance, time workout = Workout.objects.get(id=workoutid) diff --git a/rowers/tests/test_analysis.py b/rowers/tests/test_analysis.py index 8835ac82..c97eaf45 100644 --- a/rowers/tests/test_analysis.py +++ b/rowers/tests/test_analysis.py @@ -743,6 +743,13 @@ class WorkoutStatsTestNew(TestCase): self.c = Client() self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) + + today = datetime.date.today() + i = 0 + for w in self.user_workouts: + w.date = today-datetime.timedelta(days=i) + i += 1 + w.save() self.factory = RequestFactory() self.password = faker.word() self.u.set_password(self.password) diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 27485f46..19b96a23 100644 Binary files a/rowers/tests/testdata/testdata.tcx.gz and b/rowers/tests/testdata/testdata.tcx.gz differ diff --git a/rowers/uploads.py b/rowers/uploads.py index 606d5a9e..a49b20fc 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -148,6 +148,8 @@ def do_sync(w, options, quick=False): if options['nkid'] != 0 and options['nkid'] != '': # pragma: no cover w.uploadedtonk = options['nkid'] w.save() + record = SyncRecord(workout=w,nkid=options['nkid']) + record.save() except KeyError: pass @@ -182,6 +184,8 @@ def do_sync(w, options, quick=False): # upload_to_c2 = False do_c2_export = False w.save() + record = SyncRecord(workout=w,c2id=options['c2id']) + record.save() except KeyError: pass diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 882e7412..7b599b43 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -931,9 +931,11 @@ def boxplotdata(workouts, options): largerthan=False) datadf.dropna(axis=0, how='any', inplace=True) + datadf = datadf[datadf['workoutid'].isin(ids) == True] datadf['workoutid'].replace(datemapping, inplace=True) datadf.rename(columns={"workoutid": "date"}, inplace=True) + datadf['date'] = pd.to_datetime(datadf['date'], errors='coerce') datadf = datadf.dropna(subset=['date']) datadf = datadf.sort_values(['date'])