Private
Public Access
1
0

adding courses upload and course delete

This commit is contained in:
Sander Roosendaal
2018-02-20 22:50:34 +01:00
parent 00a6dae6aa
commit d3e3925625
10 changed files with 382 additions and 47 deletions

View File

@@ -162,8 +162,10 @@ from geopy.geocoders import Nominatim
geolocator = Nominatim() geolocator = Nominatim()
def createcourse(manager,name,polygons): def createcourse(
c = GeoCourse(manager=manager,name=name) manager,name,polygons,notes=''):
c = GeoCourse(manager=manager,name=name,notes=notes)
c.save() c.save()
i = 0 i = 0
@@ -186,4 +188,5 @@ def createcourse(manager,name,polygons):
obj.save() obj.save()
j += 1 j += 1
i += 1 i += 1
return c

View File

@@ -1,7 +1,7 @@
from django import forms from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.admin.widgets import FilteredSelectMultiple
from rowers.models import Workout,Rower,Team,PlannedSession from rowers.models import Workout,Rower,Team,PlannedSession
from rowers.rows import validate_file_extension,must_be_csv,validate_image_extension from rowers.rows import validate_file_extension,must_be_csv,validate_image_extension,validate_kml
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.admin.widgets import AdminDateWidget from django.contrib.admin.widgets import AdminDateWidget
@@ -55,7 +55,21 @@ class ImageForm(forms.Form):
from django.forms.widgets import HiddenInput from django.forms.widgets import HiddenInput
super(ImageForm, self).__init__(*args, **kwargs) super(ImageForm, self).__init__(*args, **kwargs)
# The form used for uploading images
class CourseForm(forms.Form):
name = forms.CharField(max_length=150,label='Course Name')
file = forms.FileField(required=False,
validators=[validate_kml])
notes = forms.CharField(required=False,
max_length=200,label='Course Notes',
widget=forms.Textarea)
def __init__(self, *args, **kwargs):
from django.forms.widgets import HiddenInput
super(CourseForm, self).__init__(*args, **kwargs)
# The form used for uploading files # The form used for uploading files
class DocumentsForm(forms.Form): class DocumentsForm(forms.Form):
title = forms.CharField(required=False) title = forms.CharField(required=False)

View File

@@ -757,7 +757,6 @@ def course_map(course):
]""" ]"""
print pcoordinates
script = """ script = """
<script> <script>

View File

@@ -664,7 +664,7 @@ class GeoCourse(models.Model):
manager = models.ForeignKey(Rower) manager = models.ForeignKey(Rower)
name = models.CharField(max_length=150,blank=True) name = models.CharField(max_length=150,blank=True)
country = models.CharField(max_length=150,blank=True) country = models.CharField(max_length=150,blank=True)
notes = models.CharField(blank=True,max_length=200,verbose_name='Course Notes')
def __unicode__(self): def __unicode__(self):
name = self.name name = self.name
return u'{name}'.format(name=name) return u'{name}'.format(name=name)

View File

@@ -69,6 +69,13 @@ def must_be_csv(value):
if not ext in valid_extensions: if not ext in valid_extensions:
raise ValidationError(u'File not supported!') raise ValidationError(u'File not supported!')
def validate_kml(value):
import os
ext = os.path.splitext(value.name)[1]
valid_extensions = ['.kml','.KML']
if not ext in valid_extensions:
raise ValidationError(u'File not supported!')
def handle_uploaded_image(i): def handle_uploaded_image(i):
import StringIO import StringIO

View File

@@ -0,0 +1,252 @@
{% extends "base.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 content %}
<div id="id_dropregion" class="grid_12 alpha 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" action="{{ formloc }}" method="post">
<div id="left" class="grid_6 alpha">
<h1>Upload KML Course File</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
<input class="button green" type="submit" value="Submit">
</div>
</div>
<div id="right" class="grid_6 omega">
&nbsp;
</div>
</form>
</div>
{% 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());
};
});});
$('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("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="120" height="100">'
);
$.ajax({
data: data,
type: $(this).attr('method'),
url: '/rowers/courses/upload',
contentType: false,
processData: false,
error: function(result) {
$("#id_waiting").replaceWith(
'<div id="id_failed" class="grid_12 alpha message">Your upload failed</div>'
);
setTimeout(function() {
location.reload();
},1000);
},
success: function(result) {
console.log('got something back');
console.log(result);
if (result.result == 1) {
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+'&nbsp; <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 %}

View File

@@ -9,7 +9,13 @@
{% block og_title %}{{ course.name }} {% endblock %} {% block og_title %}{{ course.name }} {% endblock %}
{% block content %} {% block content %}
<div class="grid_12 alpha"> <div class="grid_12 alpha">
{% if nosessions %}
<div class="grid_2 alpha">
<a class="button small red" href="/rowers/courses/{{ course.id }}/delete">Delete</a>
</div>
{% endif %}
</div>
<div class="grid_12 alpha">
<h1>{{ course.name }}</h1> <h1>{{ course.name }}</h1>

View File

@@ -85,26 +85,12 @@
<div class="grid_6 alpha"> <div class="grid_6 alpha">
{% if rankingonly and not team %}
<div class="grid_2 prefix_1 alpha"> <div class="grid_2 prefix_1 alpha">
<a class="button small green" href="/rowers/list-courses">All Courses</a> <a class="button small green" href="/rowers/courses/upload">Add Course</a>
</div>
{% elif not team %}
<div class="grid_2 prefix_1 alpha">
<a class="button small green" href="/rowers/list-courses/ranking">Ranking Pieces Only</a>
</div>
{% endif %}
<div class="grid_2 suffix_1 omega">
<a class="button small gray" href="/rowers/courses-join-select">Glue Courses</a>
</div> </div>
<p>&nbsp;</p> <p>&nbsp;</p>
{% if team %} <form id="searchform" action="/rowers/list-courses/"
<form id="searchform" action="/rowers/list-courses/team/{{ team.id }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
method="get" accept-charset="utf-8">
{% else %}
<form id="searchform" action="/rowers/list-courses/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
method="get" accept-charset="utf-8"> method="get" accept-charset="utf-8">
{% endif %}
<div class="grid_3 prefix_1 alpha"> <div class="grid_3 prefix_1 alpha">
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search"> <input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
</div> </div>
@@ -116,26 +102,6 @@
</form> </form>
</div> </div>
<div class="grid_2 omega"> <div class="grid_2 omega">
<span class="button gray small"> &nbsp;
{% if courses.has_previous %} </div>
{% if request.GET.q %}
<a class="wh" href="?page={{ courses.previous_page_number }}&q={{ request.GET.q }}">&lt;</a>
{% else %}
<a class="wh" href="?page={{ courses.previous_page_number }}">&lt;</a>
{% endif %}
{% endif %}
<span>
Page {{ courses.number }} of {{ courses.paginator.num_pages }}.
</span>
{% if courses.has_next %}
{% if request.GET.q %}
<a class="wh" href="?page={{ courses.next_page_number }}&q={{ request.GET.q }}">&gt;</a>
{% else %}
<a class="wh" href="?page={{ courses.next_page_number }}">&gt;</a>
{% endif %}
{% endif %}
</span>
{% endblock %} {% endblock %}

View File

@@ -144,6 +144,7 @@ urlpatterns = [
url(r'^list-workouts/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.workouts_view), url(r'^list-workouts/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.workouts_view),
url(r'^list-workouts/$',views.workouts_view), url(r'^list-workouts/$',views.workouts_view),
url(r'^list-courses/$',views.courses_view), url(r'^list-courses/$',views.courses_view),
url(r'^courses/upload$',views.course_upload_view),
url(r'^addmanual/$',views.addmanual_view), url(r'^addmanual/$',views.addmanual_view),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.team_comparison_select), url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.team_comparison_select),
url(r'^team-compare-select/team/(?P<teamid>\d+)/$',views.team_comparison_select), url(r'^team-compare-select/team/(?P<teamid>\d+)/$',views.team_comparison_select),
@@ -487,6 +488,7 @@ urlpatterns = [
url(r'^sessions/(?P<timeperiod>[\w\ ]+.*)$',views.plannedsessions_view), url(r'^sessions/(?P<timeperiod>[\w\ ]+.*)$',views.plannedsessions_view),
url(r'^courses/(?P<id>\d+)/edit$',views.course_edit_view, url(r'^courses/(?P<id>\d+)/edit$',views.course_edit_view,
name='course_edit_view'), name='course_edit_view'),
url(r'^courses/(?P<id>\d+)/delete$',views.course_delete_view),
] ]
if settings.DEBUG: if settings.DEBUG:

View File

@@ -27,7 +27,7 @@ from django.http import (
) )
from django.contrib.auth import authenticate, login, logout from django.contrib.auth import authenticate, login, logout
from rowers.forms import ( from rowers.forms import (
LoginForm,DocumentsForm,UploadOptionsForm,ImageForm, LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,CourseForm,
TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm, TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm,
WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement, WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement,
LandingPageForm,PlannedSessionSelectForm,WorkoutSessionSelectForm, LandingPageForm,PlannedSessionSelectForm,WorkoutSessionSelectForm,
@@ -69,6 +69,7 @@ from rowers.models import (
) )
from rowers.metrics import rowingmetrics,defaultfavoritecharts from rowers.metrics import rowingmetrics,defaultfavoritecharts
from rowers import metrics from rowers import metrics
from rowers import courses
import rowers.uploads as uploads import rowers.uploads as uploads
from django.forms.formsets import formset_factory from django.forms.formsets import formset_factory
from django.forms import modelformset_factory from django.forms import modelformset_factory
@@ -6052,6 +6053,8 @@ def courses_view(request):
courses = GeoCourse.objects.all().order_by("country") courses = GeoCourse.objects.all().order_by("country")
# add search processing
return render(request,'list_courses.html', return render(request,'list_courses.html',
{'courses':courses, {'courses':courses,
'rower':r, 'rower':r,
@@ -8405,6 +8408,28 @@ def workout_comment_view(request,id=0):
'form':form, 'form':form,
}) })
@login_required()
def course_delete_view(request,id=0):
try:
course = GeoCourse.objects.get(id=id)
except GeoCourse.DoesNotExist:
return Http404("Course doesn't exist")
r = getrower(request.user)
if course.manager != r:
raise PermissionDenied("Access denied")
ps = PlannedSession.objects.filter(course=course)
nosessions = len(ps) == 0
if nosessions:
course.delete()
url = reverse(courses_view)
return HttpResponseRedirect(url)
@login_required() @login_required()
def course_edit_view(request,id=0): def course_edit_view(request,id=0):
try: try:
@@ -8412,7 +8437,15 @@ def course_edit_view(request,id=0):
except GeoCourse.DoesNotExist: except GeoCourse.DoesNotExist:
return Http404("Course doesn't exist") return Http404("Course doesn't exist")
r = getrower(request.user)
if course.manager != r:
raise PermissionDenied("Access denied")
ps = PlannedSession.objects.filter(course=course)
nosessions = len(ps) == 0
script,div = course_map(course) script,div = course_map(course)
return render(request, 'course_view.html', return render(request, 'course_view.html',
@@ -8420,6 +8453,7 @@ def course_edit_view(request,id=0):
'course':course, 'course':course,
'mapscript':script, 'mapscript':script,
'mapdiv':div, 'mapdiv':div,
'nosessions':nosessions,
} }
) )
@@ -8892,6 +8926,58 @@ def workout_uploadimage_view(request,id):
else: else:
return {'result':0} return {'result':0}
# Image upload
@login_required()
def course_upload_view(request):
is_ajax = False
if request.is_ajax():
is_ajax = True
r = getrower(request.user)
if request.method == 'POST':
form = CourseForm(request.POST,request.FILES)
if form.is_valid():
f = form.cleaned_data['file']
name = form.cleaned_data['name']
notes = form.cleaned_data['notes']
if f is not None:
filename,path_and_filename = handle_uploaded_file(f)
polygons = courses.kmltocourse(path_and_filename)
course = courses.createcourse(r,name,polygons,notes=notes)
os.remove(path_and_filename)
url = reverse(courses_view)
if is_ajax:
return JSONResponse({'result':1,'url':url})
else:
return HttpResponseRedirect(url)
else:
messages.error(request,'Something went wrong - no file attached')
url = reverse(course_upload_view)
if is_ajax:
return JSONResponse({'result':0,'url':0})
else:
return HttpResponseRedirect(url)
else:
messages.error(request,'Form is not valid')
return render(request,'course_form.html',
{'form':form,
})
else:
if not is_ajax:
form = CourseForm()
return render(request,'course_form.html',
{'form':form,
})
else:
return {'result':0}
# Generic chart creation # Generic chart creation