better more intuitive course update
This commit is contained in:
@@ -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')
|
||||
|
||||
100
rowers/rows.py
100
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):
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<p>Drag and drop files here </p>
|
||||
</div>
|
||||
<div id="id_drop-files" class="grid_12 alpha drop-files">
|
||||
<form id="file_form" enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||
<form id="file_form" enctype="multipart/form-data" method="post">
|
||||
{% if form.errors %}
|
||||
<p style="color: red;">
|
||||
Please correct the error{{ form.errors|pluralize }} below.
|
||||
@@ -242,6 +242,8 @@
|
||||
$("#id_waiting").replaceWith(
|
||||
'<div id="id_failed" class="grid_12 alpha message">Your upload failed</div>'
|
||||
);
|
||||
console.log(data);
|
||||
setTimeout(1000);
|
||||
setTimeout(function() {
|
||||
location.reload();
|
||||
},1000);
|
||||
|
||||
319
rowers/templates/course_form_update.html
Normal file
319
rowers/templates/course_form_update.html
Normal file
@@ -0,0 +1,319 @@
|
||||
{% extends "newbase.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}File loading{% endblock %}
|
||||
|
||||
{% block meta %}
|
||||
<script type='text/javascript'
|
||||
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||
</script>
|
||||
<script type='text/javascript'
|
||||
src='https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js'>
|
||||
</script>
|
||||
<script>
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<h1>Upload KML Course File</h1>
|
||||
|
||||
<ul class="main-content">
|
||||
<li class="grid_4">
|
||||
<div id="id_dropregion watermark invisible">
|
||||
<p>Drag and drop files here </p>
|
||||
</div>
|
||||
<div id="id_drop-files" class="grid_12 alpha drop-files">
|
||||
<form id="file_form" enctype="multipart/form-data" method="post">
|
||||
{% if form.errors %}
|
||||
<p style="color: red;">
|
||||
Please correct the error{{ form.errors|pluralize }} below.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
<input class="button" type="submit" value="Submit">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
<h2>How-to</h2>
|
||||
<p>
|
||||
Courses allow you to mark the start & finish lines of your
|
||||
test pieces and measure the time spent on the course (as opposed
|
||||
to the total duration of a workout). This allows you to row and rank
|
||||
marked courses.
|
||||
|
||||
To create a course, you use <a href="https://www.google.com/earth/">Google Earth</a>
|
||||
to mark the start and finish lines using polygons. The process is identical
|
||||
to creating custom courses for the
|
||||
<a href="http://performancephones.com/crewnerd/">CrewNerd</a>
|
||||
app.
|
||||
|
||||
</p>
|
||||
|
||||
<p>CrewNerd has published a nice video tutorial of the process.
|
||||
<a href="https://youtu.be/whhWFmMJbhM">Click here</a> to see the video. The part
|
||||
we're interested in starts at 2:05.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In addition to start and finish areas, on rowsandall.com you can add additional
|
||||
polygons to mark areas that you must pass (in that order). This allows for
|
||||
courses with turns around buoys, respecting buoy lines, or respecting traffic
|
||||
patterns on rivers and lakes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ul>
|
||||
<li>Open Google Earth</li>
|
||||
<li>Create a folder "Courses" under "Temporary Places" or under "My Places"</li>
|
||||
<li>Create a folder for each Course under "Courses", and for each course:</li>
|
||||
<li>Create Start polygon</li>
|
||||
<li>Optional: Create First "must row through" polygon</li>
|
||||
<li>Optional: Create subsequent "must row through" polygons</li>
|
||||
<li>Create Finish polygon</li>
|
||||
<li>Save "Courses" as KML file</li>
|
||||
<li>Upload the file to rowsandall.com using the "Add Courses" button</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>You are allowed to have multiple courses in one KML file.
|
||||
Your CrewNerd "courses.kml" file works out of the box</p>
|
||||
|
||||
<p>The site doesn't test for duplicate courses.</p>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% include 'menu_racing.html' %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block scripts %}
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script>
|
||||
var td = new FormData();
|
||||
var formdatasetok = false;
|
||||
try {
|
||||
td.set('aap','noot');
|
||||
formdatasetok = true;
|
||||
console.log('FormData.set OK');
|
||||
}
|
||||
catch(err) {
|
||||
console.log('FormData.set not OK');
|
||||
formdatasetok = false;
|
||||
}
|
||||
|
||||
if (!formdatasetok) {
|
||||
$("#id_dropregion").remove();
|
||||
}
|
||||
|
||||
if (formdatasetok) {
|
||||
|
||||
$(document).ready(function() {
|
||||
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
console.log("CSRF token",csrftoken);
|
||||
|
||||
function csrfSafeMethod(method) {
|
||||
// these HTTP methods do not require CSRF protection
|
||||
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
||||
}
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log("Loading dropper");
|
||||
jQuery.event.props.push('dataTransfer');
|
||||
|
||||
$(window).on('dragenter', function() {
|
||||
$("#id_drop-files").css("background-color","#E9E9E4");
|
||||
$("#id_dropregion").addClass("watermark").removeClass("invisible");})
|
||||
|
||||
$(window).on('dragleave', function() {
|
||||
$("#id_drop-files").css("background-color","#FFFFFF");
|
||||
$("#id_dropregion").removeClass("watermark").addClass("invisible");})
|
||||
|
||||
var frm = $("#file_form");
|
||||
|
||||
if( window.FormData === undefined ) {
|
||||
console.log('no formdata');
|
||||
alert("No FormData");
|
||||
} else {
|
||||
console.log('we have formdata');
|
||||
}
|
||||
|
||||
var data = new FormData(frm[0]);
|
||||
|
||||
|
||||
$('#id_file').on('change', function(evt) {
|
||||
var f = this.files[0];
|
||||
console.log(f);
|
||||
var istcx = false;
|
||||
var isgzip = false;
|
||||
var size1 = 10485760;
|
||||
var size2 = 1048576;
|
||||
if ((/\.(tcx|TCX)/i).test(f.name)) {
|
||||
istcx = true;
|
||||
console.log('tcx');
|
||||
if ((/\.(gz|GZ)/i).test(f.name)) {
|
||||
isgzip = true;
|
||||
console.log('gzip');
|
||||
size1 /= 5;
|
||||
size2 /= 5;
|
||||
}
|
||||
}
|
||||
console.log(size1)
|
||||
console.log(size2)
|
||||
if (f.size > size1) {
|
||||
alert("File Size must be smaller than 10 MB");
|
||||
this.value = null;
|
||||
} else {
|
||||
|
||||
if (f.size > size2) {
|
||||
$('#id_offline').val('True');
|
||||
$('#id_offline').prop('checked','True');
|
||||
data.set($('#id_offline').attr('name'),$('#id_offline').prop('checked'));
|
||||
console.log("Set offline to True");
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$('input').each(function( i ) {
|
||||
$(this).change(function() {
|
||||
if ($(this).attr('type') == 'checkbox') {
|
||||
data.set($(this).attr('name'),$(this).prop('checked'));
|
||||
console.log($(this).attr('id'),$(this).attr('name'),$(this).prop('checked'));
|
||||
} else {
|
||||
data.set($(this).attr('name'),$(this).val());
|
||||
if ($(this).attr('id') == 'id_file') {
|
||||
data.set("file",this.files[0]);
|
||||
}
|
||||
console.log($(this).attr('name'),$(this).val());
|
||||
console.log(data)
|
||||
};
|
||||
});});
|
||||
|
||||
$('textarea').each(function( i ) {
|
||||
$(this).change(function() {
|
||||
data.set($(this).attr('name'),$(this).val());
|
||||
console.log($(this).attr('name'),$(this).val());
|
||||
});
|
||||
});
|
||||
|
||||
$('select').each(function( i ) {
|
||||
console.log($(this).attr('name'),$(this).val());
|
||||
$(this).change(function() {
|
||||
data.set($(this).attr('name'),$(this).val());
|
||||
console.log($(this).attr('id'),$(this).attr('name'),$(this).val());
|
||||
});
|
||||
});
|
||||
|
||||
frm.submit(function() {
|
||||
console.log(data)
|
||||
console.log("Form submission");
|
||||
$(data.values()).each(function(value) {
|
||||
console.log(value);
|
||||
});
|
||||
|
||||
$("#id_drop-files").replaceWith(
|
||||
'<div id="id_waiting"><img src="/static/img/rowingtimer.gif" width="60" height="50" style="width:60px">'
|
||||
);
|
||||
$.ajax({
|
||||
data: data,
|
||||
type: $(this).attr('method'),
|
||||
url: '/rowers/courses/{{ course.id }}/update/',
|
||||
contentType: false,
|
||||
processData: false,
|
||||
error: function(result) {
|
||||
$("#id_waiting").replaceWith(
|
||||
'<div id="id_failed" class="grid_12 alpha message">Your upload failed</div>'
|
||||
);
|
||||
console.log(data);
|
||||
setTimeout(1000);
|
||||
setTimeout(function() {
|
||||
location.reload();
|
||||
},1000);
|
||||
},
|
||||
success: function(result) {
|
||||
console.log('got something back');
|
||||
console.log(result);
|
||||
if (result.result == 1) {
|
||||
setTimeout(1000);
|
||||
window.location.href = result.url;
|
||||
} else {
|
||||
console.log(result," reloading");
|
||||
location.reload();
|
||||
};
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
$('#id_drop-files').bind({
|
||||
drop: function(e) {
|
||||
e.preventDefault();
|
||||
console.log("you dropped something");
|
||||
var files = e.dataTransfer.files;
|
||||
console.log(files[0]);
|
||||
|
||||
var f = files[0];
|
||||
var istcx = false;
|
||||
var isgzip = false;
|
||||
var size1 = 10485760;
|
||||
var size2 = 1048576;
|
||||
if ((/\.(tcx|TCX)/i).test(f.name)) {
|
||||
istcx = true;
|
||||
console.log('tcx');
|
||||
if ((/\.(gz|GZ)/i).test(f.name)) {
|
||||
isgzip = true;
|
||||
console.log('gzip');
|
||||
size1 /= 5;
|
||||
size2 /= 5;
|
||||
}
|
||||
}
|
||||
console.log(f);
|
||||
console.log(size1)
|
||||
console.log(size2)
|
||||
if (f.size > size1) {
|
||||
alert("File Size must be smaller than 10 MB");
|
||||
$("#id_file").value = 0;
|
||||
return false;
|
||||
}
|
||||
data.set("file",f);
|
||||
// data.append("file",f);
|
||||
|
||||
$("#id_file").replaceWith('<div id="id_file">'+files[0].name+' <a class="remove" href="javascript:void(0);"><b><font color="red">X</font></b></a></div>');
|
||||
},
|
||||
mouseenter:function(){$("#id_drop-files").css("background-color","#E9E9E4");},
|
||||
mouseleave:function(){$("#id_drop-files").css("background-color","#FFFFFF");},
|
||||
dragover:function(e){
|
||||
e.preventDefault();
|
||||
$("#id_drop-files").css("background-color","#E9E9E4");},
|
||||
dragleave:function(e){ e.preventDefault();},
|
||||
});
|
||||
$(document).on("click", "a.remove", function() {
|
||||
$(this).parent().replaceWith('<td><input id="id_file" name="file" type="file" /></td>');
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
@@ -30,7 +30,7 @@
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<input class="button green" type="submit" value="Submit">
|
||||
<input class="button" type="submit" value="Submit">
|
||||
</form>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
|
||||
58
rowers/templates/course_replace_confirm.html
Normal file
58
rowers/templates/course_replace_confirm.html
Normal file
@@ -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 %}
|
||||
|
||||
<h1>Replace {{ course.name }}</h1>
|
||||
|
||||
<ul class="main-content">
|
||||
|
||||
<li class="grid_2">
|
||||
<p>
|
||||
This updates the course {{ course.name }} with the course markers as shown on
|
||||
the map below.
|
||||
</p>
|
||||
<form id="course_form" method="post">
|
||||
<form id="course_form" method="post">
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<input class="button" type="submit" value="Submit">
|
||||
</form>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
{{ mapscript|safe }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
{{ mapscript|safe }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% include 'menu_racing.html' %}
|
||||
{% endblock %}
|
||||
@@ -128,7 +128,7 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
<li id="course-view">
|
||||
<a href="/rowers/courses/{{ course.id }}/replace/">
|
||||
<a href="/rowers/courses/{{ course.id }}/update/">
|
||||
<i class="fas fa-map-marked-alt fa-fw"></i> Update Markers</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@@ -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<id>\d+)/update/(?P<newid>\d+)/',views.course_update_confirm,name='course_update_confirm'),
|
||||
re_path(r'^courses/(?P<id>\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<id>\d+)/$',views.standards_upload_view,name='standards_upload_view'),
|
||||
re_path(r'^workout/addmanual/(?P<raceid>\d+)/$',views.addmanual_view,name='addmanual_view'),
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user