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
+
+
+
+
+ | Time |
+ Distance |
+ Date |
+
+
+
+ {% for record in ownrecords %}
+
+ | {{ record.duration |durationprint:"%H:%M:%S.%f" }} |
+ {{ record.distance }} m |
+ {{ record.workoutid|workoutdate }} |
+
+
+
+ |
+
+ {% endfor %}
+
+
+
+
+{% 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' %}
+
+

+
+ {% elif challenge.challenge.sessiontype == 'fastest_distance' %}
+
+

+
+ {% elif challenge.challenge.sessiontype != 'race' %}
+
+

+
+
+ {% 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
+
{{ 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