diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index cd4cab81..804ebc52 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -926,6 +926,164 @@ def interactive_histoall(theworkouts, histoparam, includereststrokes, def course_map(course): +<<<<<<< HEAD +======= + latmean, lonmean, coordinates = course_coord_center(course) + if course.with_cn_nav_waypoints: + latmean, lonmean, coordinates = course_coord_crewnerd_navigation(course) + lat_min, lat_max, long_min, long_max = course_coord_maxmin(course) + + coordinates = course_spline(coordinates) + + scoordinates = "[" + + for index, row in coordinates.iterrows(): + scoordinates += """[{x},{y}], + """.format( + x=row['latitude'], + y=row['longitude'] + ) + + scoordinates += "]" + + polygons = GeoPolygon.objects.filter( + course=course).order_by("order_in_course") + + plabels = '' + + for p in polygons: + coords = polygon_coord_center(p) + + plabels += """ + var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap); + marker.bindPopup("{name}"); + + """.format( + latbegin=coords[0], + longbegin=coords[1], + name=p.name + ) + + pcoordinates = """[ + """ + + for p in polygons: + pcoordinates += """[ + [""" + + points = GeoPoint.objects.filter(polygon=p).order_by("order_in_poly") + + for pt in points: + pcoordinates += "[{x},{y}],".format( + x=pt.latitude, + y=pt.longitude + ) + + # remove last comma + pcoordinates = pcoordinates[:-1] + pcoordinates += """] + ], + """ + + pcoordinates += """ + ]""" + + script = """ + + """.format( + id=course.id, + latmean=latmean, + lonmean=lonmean, + scoordinates=scoordinates, + pcoordinates=pcoordinates, + plabels=plabels + ) + + div = """ +
+ """.format( + id=course.id, + ) +>>>>>>> develop course_dict = GeoCourseSerializer(course).data diff --git a/rowers/models.py b/rowers/models.py index b8cfeda2..483df158 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -4158,6 +4158,7 @@ class IndoorVirtualRaceResult(models.Model): class CourseTestResult(models.Model): userid = models.IntegerField(default=0) + courseid = models.IntegerField(default=0) workoutid = models.IntegerField(null=True) plannedsession = models.ForeignKey( PlannedSession, on_delete=models.CASCADE) @@ -4167,6 +4168,13 @@ class CourseTestResult(models.Model): startsecond = models.FloatField(default=0) endsecond = models.FloatField(default=0) + def save(self, *args, **kwargs): + if self.userid == 0: + w = Workout.objects.get(id=self.workoutid) + self.userid = w.user.id + + super(CourseTestResult, self).save(*args, **kwargs) + class IndoorVirtualRaceResultForm(ModelForm): class Meta: diff --git a/rowers/tasks.py b/rowers/tasks.py index 6572a1dd..f42891c9 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -1149,9 +1149,11 @@ def handle_check_race_course(self, record.duration = totaltime_sec_to_string(coursetimeseconds) record.distance = int(coursemeters) record.workoutid = workoutid + record.courseid = courseid record.startsecond = startsecond record.endsecond = endsecond record.points = points + record.coursecompleted = 1 record.save() if summary: # pragma: no cover @@ -1178,7 +1180,6 @@ def handle_check_race_course(self, workout.summary = summary workout.save() - if successemail: # pragma: no cover handle_sendemail_coursesucceed( useremail, userfirstname, logfile, workoutid diff --git a/rowers/templates/course_view.html b/rowers/templates/course_view.html index 109a1db3..decc0089 100644 --- a/rowers/templates/course_view.html +++ b/rowers/templates/course_view.html @@ -136,7 +136,36 @@

{% endif %} - {% endif %} + {% endif %} + {% if ownrecords %} +
  • +

    Own (Private) Results

    +

    + + + + + + + + + + {% for record in ownrecords %} + + + + + + + {% endfor %} + +
    TimeDistanceDate
    {{ record.duration |durationprint:"%H:%M:%S.%f" }}{{ record.distance }} m{{ record.workoutid|workoutdate }} + + +
    +

    +
  • +{% endif %} {% endblock %} diff --git a/rowers/templates/courses_challenges.html b/rowers/templates/courses_challenges.html new file mode 100644 index 00000000..dec869a1 --- /dev/null +++ b/rowers/templates/courses_challenges.html @@ -0,0 +1,105 @@ +{% extends "newbase.html" %} +{% load static %} +{% load rowerfilters %} +{% load leaflet_tags %} + +{% block meta %} +{% leaflet_js %} +{% leaflet_css %} +{% endblock %} + +{% block title %}Rowsandall Virtual Challenges{% endblock %} + +{% block scripts %} + + +{% endblock %} + +{% block main %} + +
      +
    • +

      Courses you might like

      +
    • +
    • +

      + All Courses +

      + Courses I like +

      +
    • +{% for course in coursesdicts %} +
    • + +

      {{ course.course.name }}

      +
      +

      {{ course.course.country }}

      +

      {{ course.course.distance }}m

      +
      + {{ course.div|safe}} + {{ course.script|safe}} +
      +
    • +{% endfor %} +
    • +

      Interesting Challenges

      +
    • +
    • +

      + All Active Challenges +

      + Nearby Challenges +

      +
    • +{% for challenge in challengesdicts %} +
    • + +

      {{ challenge.challenge.name }}

      +
      +

      {{ challenge.challenge.startdate|date:"Y-m-d" }} + {{ challenge.challenge.start_time|time:"H:i e" }} + to + {{ challenge.challenge.enddate|date:"Y-m-d" }} + {{ challenge.challenge.end_time|time:"H:i e" }} + ({{ challenge.challenge.timezone }})

      +

      {% if challenge.challenge.sessiontype == 'fastest_time' %} + Time Challenge: To be rowed on the water + {% elif challenge.challenge.sessiontype == 'fastest_distance' %} + Distance Challenge: To be rowed on the water + {% elif challenge.challenge.sessiontype != 'race' %} + Indoor Race: To be rowed on a Concept2 ergometer + {% endif %} +

      + {% if challenge.challenge.sessiontype == 'fastest_time' %} +
      + Marked Course +
      + {% elif challenge.challenge.sessiontype == 'fastest_distance' %} +
      + Marked Course +
      + {% elif challenge.challenge.sessiontype != 'race' %} +
      + Marked Course +
      + + {% endif %} +
      + {{ challenge.div|safe}} + {{ challenge.script|safe}} +
      +
    • +{% endfor %} + +
    + +{% endblock %} + +{% block sidebar %} +{% include 'menu_racing.html' %} +{% endblock %} diff --git a/rowers/templates/plannedsessionview.html b/rowers/templates/plannedsessionview.html index 2389ffcc..3313c733 100644 --- a/rowers/templates/plannedsessionview.html +++ b/rowers/templates/plannedsessionview.html @@ -172,7 +172,7 @@ {% if coursescript %}
  • -

    Course

    +

    {{ plannedsession.course.name }}

    {{ coursediv|safe }} {{ coursescript|safe }} diff --git a/rowers/urls.py b/rowers/urls.py index 6f26b875..ca762683 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -311,6 +311,8 @@ urlpatterns = [ name='workouts_view'), re_path(r'^list-workouts/user/(?P\d+)/$', views.workouts_view, name='workouts_view'), + re_path(r'^courses/$', views.courses_challenges_view, + name='courses_challenges_view'), re_path(r'^virtualevents/$', views.virtualevents_view, name='virtualevents_view'), re_path(r'^virtualevent/createchoice/$', TemplateView.as_view( diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 03bedb87..86e353ca 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -410,12 +410,15 @@ def trendflexdata(workouts, options, userid=0): except (ValueError, AttributeError): # pragma: no cover return ('', 'Error: not enough data') else: # pragma: no cover - bins = np.arange(datadf['days ago'].min()-binsize, - datadf['days ago'].max()+binsize, - binsize, - ) - groups = datadf.groupby(pd.cut(datadf['days ago'], bins, - labels=False)) + try: + bins = np.arange(datadf['days ago'].min()-binsize, + datadf['days ago'].max()+binsize, + binsize, + ) + groups = datadf.groupby(pd.cut(datadf['days ago'], bins, + labels=False)) + except (ValueError, AttributeError): # pragma: no cover + return ('', 'Error: not enough data') xvalues = [] yvalues = [] diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py index a3a424ad..e44609ac 100644 --- a/rowers/views/planviews.py +++ b/rowers/views/planviews.py @@ -2332,7 +2332,6 @@ def plannedsession_view(request, id=0, userid=0): if ps.sessiontype == 'coursetest': # pragma: no cover vs = CourseTestResult.objects.filter(plannedsession=ps, workoutid=w.id) - if vs: for record in vs: if record.workoutid == w.id: diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 965bd58a..860c58cd 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -8,10 +8,99 @@ from django import forms from rowers.plannedsessions import timefield_to_seconds_duration from rowers.courses import getnearestraces, getnearestcourses,coursetokml, coursestokml +from random import sample + +# landing page for challenges & courses +def courses_challenges_view(request): + r = getrower(request.user) + g = GeoIP2() + + ip = request.META.get('HTTP_X_REAL_IP', '1.1.1.1') + try: + lat_lon = g.lat_lon(ip) + city = g.city(ip) + except: # pragma: no cover + lat_lon = None + city = { + 'city': '', + 'country_name': '', + 'time_zone': '', + } + + courses = GeoCourse.objects.all().order_by("country", "name", "distance") + nearby_courses = getnearestcourses(lat_lon, courses, whatisnear=2000) + liked_courses = GeoCourse.objects.filter(followers=r) + courses = GeoCourse.objects.filter(id__in=[course.id for course in nearby_courses]) | liked_courses + + if courses.count() >= 3: + courses = sample(list(courses),3) + else: + courses = GeoCourse.objects.all().order_by("country", "name", "distance") + + coursesdicts = [] + for course in courses: + script, div = course_map(course) + coursesdicts.append({ + 'course': course, + 'script': script, + 'div': div, + }) + + allchallenges = VirtualRace.objects.all().order_by("-startdate") + totalnrchallenges = allchallenges.count() + challenges = VirtualRace.objects.filter(startdate__gte=timezone.now()) + challenges2 = VirtualRace.objects.filter(startdate__lte=timezone.now(), + evaluation_closure__gte=timezone.now()-datetime.timedelta(days=3)) + + challenges = challenges | challenges2 + count = 3 + if totalnrchallenges > count: + allchallenges = list(allchallenges) + while len(challenges) < count: + try: + challenges = list(challenges)+sample(allchallenges, count-len(challenges)) + except ValueError: + count = count-1 + challenges = list(set(challenges)) + else: + challenges = VirtualRace.objects.all() + count = challenges.count() + + challenges = sample(list(challenges),count) + + challengesdicts = [] + for challenge in challenges: + script = '' + div = '' + if challenge.course: + script, div = course_map(challenge.course) + + challengesdicts.append( + { + 'script': script, + 'div': div, + 'challenge': challenge, + } + ) + + breadcrumbs = [ + { + 'url': reverse('courses_challenges_view'), + 'name': 'Courses and Challenges' + } + ] + + + return render(request, "courses_challenges.html", + { + 'coursesdicts': coursesdicts, + 'rower': r, + 'challengesdicts': challengesdicts, + 'breadcrumbs': breadcrumbs, + }) + # List Courses - - def courses_view(request): r = getrower(request.user) g = GeoIP2() @@ -280,6 +369,13 @@ def course_view(request, id=0): workoutid__isnull=False, coursecompleted=True).order_by("duration", "-distance") + # get own training results + ownrecords = CourseTestResult.objects.filter( + courseid = course.id, + userid = r.id, + coursecompleted=True + ).order_by("duration", "-distance") + if request.user.is_authenticated: notsharing = Rower.objects.filter( share_course_results=False).exclude(id=r.id) @@ -371,6 +467,7 @@ def course_view(request, id=0): 'mapdiv': div, 'nosessions': False, 'records': records, + 'ownrecords': ownrecords, 'rower': r, 'form': form, 'onlyme': onlyme, diff --git a/templates/newbase.html b/templates/newbase.html index 54db92b3..baa53d37 100644 --- a/templates/newbase.html +++ b/templates/newbase.html @@ -206,8 +206,8 @@
  • - -  Challenges + +  Challenges, Courses