diff --git a/rowers/forms.py b/rowers/forms.py
index 440e38cb..27dc4158 100644
--- a/rowers/forms.py
+++ b/rowers/forms.py
@@ -203,7 +203,7 @@ class ImageForm(forms.Form):
# The form used for uploading images
class CourseForm(forms.Form):
- name = forms.CharField(max_length=150,label='Course Name')
+ name = forms.CharField(max_length=150,label='Course Name',required=False)
file = forms.FileField(required=False,
validators=[validate_kml])
notes = forms.CharField(required=False,
@@ -214,6 +214,13 @@ class CourseForm(forms.Form):
from django.forms.widgets import HiddenInput
super(CourseForm, self).__init__(*args, **kwargs)
+class CourseConfirmForm(forms.Form):
+ BOOL_CHOICES = ((True, 'Yes'), (False, 'No'))
+ doupdate = forms.TypedChoiceField(
+ initial=False,
+ coerce=lambda x: x =='True', choices=((False, 'No'), (True, 'Yes')), widget=forms.RadioSelect,
+ label='Update Course with new markers?')
+
# The form used for uploading files
class StandardsForm(forms.Form):
name = forms.CharField(max_length=150,label='Course Name')
diff --git a/rowers/rows.py b/rowers/rows.py
index fa34cf00..9a70073f 100644
--- a/rowers/rows.py
+++ b/rowers/rows.py
@@ -15,18 +15,18 @@ import uuid
from django.core.exceptions import ValidationError
def format_pace_tick(x,pos=None):
- minu=int(x/60)
- sec=int(x-minu*60.)
- sec_str=str(sec).zfill(2)
- template='%d:%s'
- return template % (minu,sec_str)
+ minu=int(x/60)
+ sec=int(x-minu*60.)
+ sec_str=str(sec).zfill(2)
+ template='%d:%s'
+ return template % (minu,sec_str)
def format_time_tick(x,pos=None):
- hour=int(x/3600)
- min=int((x-hour*3600.)/60)
- min_str=str(min).zfill(2)
- template='%d:%s'
- return template % (hour,min_str)
+ hour=int(x/3600)
+ min=int((x-hour*3600.)/60)
+ min_str=str(min).zfill(2)
+ template='%d:%s'
+ return template % (hour,min_str)
def format_pace(x,pos=None):
if isinf(x) or isnan(x):
@@ -56,12 +56,12 @@ def format_time(x,pos=None):
return str1
def validate_image_extension(value):
- import os
- ext = os.path.splitext(value.name)[1].lower()
- valid_extension = ['.jpg','.jpeg','.png','.gif']
+ import os
+ ext = os.path.splitext(value.name)[1].lower()
+ valid_extension = ['.jpg','.jpeg','.png','.gif']
- if not ext in valid_extension:
- raise ValidationError(u'File not supported')
+ if not ext in valid_extension:
+ raise ValidationError(u'File not supported')
def validate_file_extension(value):
import os
@@ -88,53 +88,53 @@ def validate_kml(value):
def handle_uploaded_image(i):
- from io import StringIO, BytesIO
- from PIL import Image, ImageOps, ExifTags
- import os
- from django.core.files import File
- image_str = b''
- for chunk in i.chunks():
- image_str += chunk
+ from io import StringIO, BytesIO
+ from PIL import Image, ImageOps, ExifTags
+ import os
+ from django.core.files import File
+ image_str = b''
+ for chunk in i.chunks():
+ image_str += chunk
- imagefile = BytesIO(image_str)
+ imagefile = BytesIO(image_str)
- image = Image.open(i)
+ image = Image.open(i)
- try:
- for orientation in ExifTags.TAGS.keys():
- if ExifTags.TAGS[orientation]=='Orientation':
+ try:
+ for orientation in ExifTags.TAGS.keys():
+ if ExifTags.TAGS[orientation]=='Orientation':
break
- exif=dict(image._getexif().items())
+ exif=dict(image._getexif().items())
- except (AttributeError, KeyError, IndexError):
- # cases: image don't have getexif
- exif = {'orientation':0}
+ except (AttributeError, KeyError, IndexError):
+ # cases: image don't have getexif
+ exif = {'orientation':0}
- if image.mode not in ("L", "RGB"):
- image = image.convert("RGB")
+ if image.mode not in ("L", "RGB"):
+ image = image.convert("RGB")
- basewidth = 600
- wpercent = (basewidth/float(image.size[0]))
- hsize = int((float(image.size[1])*float(wpercent)))
- image = image.resize((basewidth,hsize), Image.ANTIALIAS)
+ basewidth = 600
+ wpercent = (basewidth/float(image.size[0]))
+ hsize = int((float(image.size[1])*float(wpercent)))
+ image = image.resize((basewidth,hsize), Image.ANTIALIAS)
- try:
- if exif[orientation] == 3:
- image=image.rotate(180, expand=True)
- elif exif[orientation] == 6:
- image=image.rotate(270, expand=True)
- elif exif[orientation] == 8:
- image=image.rotate(90, expand=True)
- except KeyError:
- pass
+ try:
+ if exif[orientation] == 3:
+ mage=image.rotate(180, expand=True)
+ elif exif[orientation] == 6:
+ image=image.rotate(270, expand=True)
+ elif exif[orientation] == 8:
+ image=image.rotate(90, expand=True)
+ except KeyError:
+ pass
- filename = hashlib.md5(imagefile.getvalue()).hexdigest()+'.jpg'
+ filename = hashlib.md5(imagefile.getvalue()).hexdigest()+'.jpg'
- filename2 = os.path.join('static/plots/',filename)
- image.save(filename2,'JPEG')
+ filename2 = os.path.join('static/plots/',filename)
+ image.save(filename2,'JPEG')
- return filename,filename2
+ return filename,filename2
def handle_uploaded_file(f):
diff --git a/rowers/templates/course_form.html b/rowers/templates/course_form.html
index aa1bb20f..1c5b25b6 100644
--- a/rowers/templates/course_form.html
+++ b/rowers/templates/course_form.html
@@ -24,7 +24,7 @@
Drag and drop files here
-
diff --git a/rowers/templates/course_replace_confirm.html b/rowers/templates/course_replace_confirm.html
new file mode 100644
index 00000000..b0b010c4
--- /dev/null
+++ b/rowers/templates/course_replace_confirm.html
@@ -0,0 +1,58 @@
+{% extends "newbase.html" %}
+{% load staticfiles %}
+{% load rowerfilters %}
+{% load leaflet_tags %}
+
+{% block meta %}
+{% leaflet_js %}
+{% leaflet_css %}
+{% endblock %}
+
+{% block scripts %}
+{% include "monitorjobs.html" %}
+{% endblock %}
+
+{% block title %}{{ course.name }} {% endblock %}
+{% block og_title %}{{ course.name }} {% endblock %}
+{% block main %}
+
+Replace {{ course.name }}
+
+
+
+ -
+
+ This updates the course {{ course.name }} with the course markers as shown on
+ the map below.
+
+
+
+ -
+
+ {{ mapdiv|safe }}
+
+
+ {{ mapscript|safe }}
+
+
+ -
+
+ {{ mapdiv|safe }}
+ {{ mapscript|safe }}
+
+
+
+
+
+{% endblock %}
+
+{% block sidebar %}
+{% include 'menu_racing.html' %}
+{% endblock %}
diff --git a/rowers/templates/menu_racing.html b/rowers/templates/menu_racing.html
index 9d115550..4ebd5e26 100644
--- a/rowers/templates/menu_racing.html
+++ b/rowers/templates/menu_racing.html
@@ -128,7 +128,7 @@
{% endif %}
-
+
Update Markers
{% endif %}
diff --git a/rowers/urls.py b/rowers/urls.py
index 68109a49..6e74b0df 100644
--- a/rowers/urls.py
+++ b/rowers/urls.py
@@ -205,6 +205,8 @@ urlpatterns = [
re_path(r'^list-courses/$',views.courses_view,name='courses_view'),
re_path(r'^list-standards/$',views.standards_view,name='standards_view'),
re_path(r'^courses/upload/$',views.course_upload_view,name='course_upload_view'),
+ re_path(r'^courses/(?P
\d+)/update/(?P\d+)/',views.course_update_confirm,name='course_update_confirm'),
+ re_path(r'^courses/(?P\d+)/update/',views.course_upload_replace_view,name='course_upload_replace_view'),
re_path(r'^standards/upload/$',views.standards_upload_view,name='standards_upload_view'),
re_path(r'^standards/upload/(?P\d+)/$',views.standards_upload_view,name='standards_upload_view'),
re_path(r'^workout/addmanual/(?P\d+)/$',views.addmanual_view,name='addmanual_view'),
diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py
index 8fd04b04..455ab0f5 100644
--- a/rowers/views/racesviews.py
+++ b/rowers/views/racesviews.py
@@ -8,6 +8,7 @@ from rowsandall_app.settings import SITE_URL
from rowers.scoring import *
from django.contrib.gis.geoip2 import GeoIP2
+from django import forms
# distance of course from lat_lon in km
def howfaris(lat_lon,course):
@@ -559,6 +560,132 @@ def virtualevent_uploadimage_view(request,id=0):
})
+@login_required()
+@permission_required('course.change_course',fn=get_course_by_pk,raise_exception=True)
+def course_upload_replace_view(request,id=0):
+ is_ajax = False
+ if request.is_ajax():
+ is_ajax = True
+
+ r = getrower(request.user)
+
+ course = get_object_or_404(GeoCourse,pk=id)
+
+
+ if request.method == 'POST':
+ form = CourseForm(request.POST,request.FILES)
+
+ if form.is_valid():
+ f = form.cleaned_data['file']
+ notes = form.cleaned_data['notes']
+ if f is not None:
+ filename, path_and_filename = handle_uploaded_file(f)
+
+ cs = courses.kmltocourse(path_and_filename)
+ os.remove(path_and_filename)
+ if cs and len(cs) > 1:
+ messages.info(request,'File contained multiple courses. We use the first one.')
+ if cs:
+ course = cs[0]
+ cname = course['name']
+ cnotes = notes+'\n\n'+course['description']
+ polygons = course['polygons']
+
+ course = courses.createcourse(r,cname,polygons,notes=cnotes)
+
+ url = reverse(course_update_confirm,
+ kwargs = {
+ 'newid':course.id,
+ 'id':id,
+ }
+ )
+ if is_ajax:
+ return JSONResponse({'result':1,'url':url})
+ else:
+ return HttpResponseRedirect(url)
+ else:
+ messages.error(request,"File does not contain a course")
+ else:
+ messages.error(request,"No file attached")
+ else:
+ messages.error(request,"Form is not valid")
+ else:
+ form = CourseForm()
+
+ form.fields['name'].widget = forms.HiddenInput()
+
+ if not is_ajax:
+ return render(request,'course_form_update.html',
+ {'form':form,
+ 'course':course,
+ 'active':'nav-racing',
+ })
+ else:
+ return {'result':0}
+
+
+@login_required()
+@permission_required('course.change_course',fn=get_course_by_pk,raise_exception=True)
+def course_update_confirm(request,id=0,newid=0):
+ course = get_object_or_404(GeoCourse,pk=id)
+ course2 = get_object_or_404(GeoCourse,pk=newid)
+ r = getrower(request.user)
+ if request.method == 'POST':
+ form = CourseConfirmForm(request.POST)
+ if form.is_valid():
+ doupdate = form.cleaned_data['doupdate']
+ if doupdate:
+ res = courses.replacecourse(course,course2)
+ messages.info(request,'All challenges with this course are updated')
+ url = reverse(course_view,
+ kwargs = {
+ 'id':course2.id,
+ })
+ return HttpResponseRedirect(url)
+ else:
+ course2.delete()
+ url = reverse(course_view,
+ kwargs = {
+ 'id':course.id,
+ })
+ return HttpResponseRedirect(url)
+ else:
+ form = CourseConfirmForm()
+ # GET call or invalid form
+ script, div = course_map(course2)
+
+
+ breadcrumbs = [
+ {
+ 'url': reverse('virtualevents_view'),
+ 'name': 'Challenges'
+ },
+ {
+ 'url': reverse(courses_view),
+ 'name': 'Courses'
+ },
+ {
+ 'url': reverse(course_view,kwargs={'id':course.id}),
+ 'name': course.name
+ },
+ {
+ 'url': reverse(course_replace_view,kwargs={'id':course.id}),
+ 'name': 'Replace Markers'
+ }
+ ]
+
+ return render(request,
+ 'course_replace_confirm.html',
+ {'course':course,
+ 'form':form,
+ 'active':'nav-racing',
+ 'breadcrumbs':breadcrumbs,
+ 'rower':r,
+ 'mapdiv':div,
+ 'mapscript':script,
+ })
+
+
# Course upload
@login_required()
def course_upload_view(request):
diff --git a/rowers/views/statements.py b/rowers/views/statements.py
index 6003cb4b..2b34446f 100644
--- a/rowers/views/statements.py
+++ b/rowers/views/statements.py
@@ -64,6 +64,7 @@ from django.contrib.auth import authenticate, login, logout
from rowers.forms import (
ForceCurveOptionsForm,HistoForm,TeamMessageForm,
LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,CourseForm,
+ CourseConfirmForm,
TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm,
WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement,
LandingPageForm,PlannedSessionSelectForm,WorkoutSessionSelectForm,