half way through cleaning up and commenting the code
This commit is contained in:
@@ -1,33 +1,5 @@
|
||||
|
||||
from django import forms
|
||||
from rowers.models import Workout
|
||||
from rows import validate_file_extension
|
||||
|
||||
class ContactForm(forms.Form):
|
||||
subject = forms.CharField()
|
||||
email = forms.EmailField(required=False)
|
||||
message = forms.CharField(widget=forms.Textarea)
|
||||
|
||||
class DocumentsForm(forms.Form):
|
||||
filetypechoices = (
|
||||
('tcx' , 'TCX'),
|
||||
('csv' , 'Painsled CSV')
|
||||
)
|
||||
title = forms.CharField(required=False)
|
||||
file = forms.FileField(required=True,
|
||||
validators=[validate_file_extension])
|
||||
workouttype = forms.ChoiceField(required=True,
|
||||
choices=Workout.workouttypes,
|
||||
initial='rower')
|
||||
fileformat = forms.ChoiceField(required=True,
|
||||
choices=filetypechoices,
|
||||
initial='csv')
|
||||
notes = forms.CharField(required=False,
|
||||
widget=forms.Textarea)
|
||||
|
||||
class Meta:
|
||||
fields = ['title','file','workouttype','fileformat']
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.db import models
|
||||
from rows import validate_file_extension
|
||||
|
||||
class Document(models.Model):
|
||||
docfile = models.FileField(upload_to='documents/%Y/%m/%d',
|
||||
validators=[validate_file_extension])
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
|
||||
def addrc(x,y,z):
|
||||
return int(x)+int(y)
|
||||
@@ -1,83 +0,0 @@
|
||||
import time
|
||||
import gzip
|
||||
import shutil
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
def format_pace_tick(x,pos=None):
|
||||
min=int(x/60)
|
||||
sec=int(x-min*60.)
|
||||
sec_str=str(sec).zfill(2)
|
||||
template='%d:%s'
|
||||
return template % (min,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)
|
||||
|
||||
def format_pace(x,pos=None):
|
||||
if isinf(x) or isnan(x):
|
||||
x=0
|
||||
|
||||
min=int(x/60)
|
||||
sec=(x-min*60.)
|
||||
|
||||
str1 = "{min:0>2}:{sec:0>4.1f}".format(
|
||||
min = min,
|
||||
sec = sec
|
||||
)
|
||||
|
||||
return str1
|
||||
|
||||
def format_time(x,pos=None):
|
||||
|
||||
|
||||
min = int(x/60.)
|
||||
sec = int(x-min*60)
|
||||
|
||||
str1 = "{min:0>2}:{sec:0>4.1f}".format(
|
||||
min=min,
|
||||
sec=sec,
|
||||
)
|
||||
|
||||
return str1
|
||||
|
||||
def validate_file_extension(value):
|
||||
import os
|
||||
ext = os.path.splitext(value.name)[1]
|
||||
valid_extensions = ['.tcx','.csv','.TCX','.CSV','.fit','.FIT','.zip','.ZIP']
|
||||
if not ext in valid_extensions:
|
||||
raise ValidationError(u'File not supported!')
|
||||
|
||||
def must_be_csv(value):
|
||||
import os
|
||||
ext = os.path.splitext(value.name)[1]
|
||||
valid_extensions = ['.csv','.CSV']
|
||||
if not ext in valid_extensions:
|
||||
raise ValidationError(u'File not supported!')
|
||||
|
||||
|
||||
def handle_uploaded_file(f):
|
||||
fname = f.name
|
||||
timestr = time.strftime("%Y%m%d-%H%M%S")
|
||||
fname = timestr+'-'+fname
|
||||
fname2 = 'media/'+fname
|
||||
with open(fname2,'wb+') as destination:
|
||||
for chunk in f.chunks():
|
||||
destination.write(chunk)
|
||||
|
||||
return fname,fname2
|
||||
|
||||
# this might work on windows
|
||||
|
||||
#import magic
|
||||
#def validate_mime_type(value):
|
||||
# supported_types=['text/csv','application/vnd.garmin.tcx+xml']
|
||||
# with magic.Magic(flags=magic.MAGIC_MIME_TYPE) as m:
|
||||
# mime_type=m.id_buffer(value.file.read())
|
||||
# value.file.seek(0)
|
||||
# if mime_type not in supported_types:
|
||||
# raise ValidationError(u'Unsupported file type.')
|
||||
@@ -1,121 +0,0 @@
|
||||
"""
|
||||
Django settings for rowsandall_app project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 1.9.5.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.9/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.9/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '&cg#y8h-8s#00ayk#gu)+l43j1j9^9r&qf$3!$x#ov@1houiph'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
]
|
||||
|
||||
MIDDLEWARE_CLASSES = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'rowsandall_app.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(BASE_DIR,'templates')],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'rowsandall_app.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.9/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'Europe/Prague'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.9/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
@@ -1,3 +0,0 @@
|
||||
graph = {{ my_data|safe }};
|
||||
|
||||
mpld3.draw_figure("fig01", graph);
|
||||
@@ -17,9 +17,7 @@ from django.conf.urls import url,include
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
from django.contrib import admin
|
||||
from rowsandall_app.views import rootview,version,rowingdata,showStaticImage,\
|
||||
add,wait,nrowingdata,waitforplot,showplot,interactiveplot
|
||||
from rowsandall_app.views import uploadfile
|
||||
from rowsandall_app.views import rootview
|
||||
from django.contrib.auth import views as auth_views
|
||||
from rowers import views as rowersviews
|
||||
|
||||
@@ -28,8 +26,6 @@ urlpatterns = [
|
||||
url(r'^admin/', admin.site.urls),
|
||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||
url(r'^$',rootview),
|
||||
url(r'^version/$',version),
|
||||
url(r'^addresult/(.+.*)/$',wait),
|
||||
url(r'^login/',auth_views.login, name='login'),
|
||||
url(r'^logout/',auth_views.logout_then_login,name='logout'),
|
||||
url(r'^password_change_done/$',auth_views.password_change_done,name='password_change_done'),
|
||||
@@ -42,12 +38,10 @@ urlpatterns = [
|
||||
url(r'^password_reset_complete/$',auth_views.password_reset_complete,name='password_reset_complete'),
|
||||
url(r'^rowers/',include('rowers.urls')),
|
||||
url(r'^cvkbrno/',include('cvkbrno.urls')),
|
||||
url(r'^add/(\d+)/(\d+)/$',add),
|
||||
url(r'^call\_back',rowersviews.rower_process_callback),
|
||||
url(r'^stravacall\_back',rowersviews.rower_process_stravacallback),
|
||||
url(r'^sporttracks\_callback',rowersviews.rower_process_sporttrackscallback),
|
||||
url(r'^twitter\_callback',rowersviews.rower_process_twittercallback),
|
||||
url(r'^interactiveplot',interactiveplot),
|
||||
url(r'^i18n/', include('django.conf.urls.i18n')),
|
||||
]
|
||||
|
||||
|
||||
@@ -1,258 +1,11 @@
|
||||
from django.http import HttpResponse,Http404,HttpResponseRedirect
|
||||
from django.template import Template, Context
|
||||
from django.template.loader import get_template
|
||||
from django.shortcuts import render, redirect, render_to_response
|
||||
from django.conf import settings
|
||||
from rowsandall_app.forms import ContactForm,DocumentsForm
|
||||
from django.core.mail import send_mail
|
||||
from django.core.urlresolvers import reverse
|
||||
from matplotlib.pyplot import figure, axes, pie, title
|
||||
from matplotlib.backends.backend_agg import FigureCanvasAgg
|
||||
from matplotlib.ticker import MultipleLocator,FuncFormatter,NullFormatter
|
||||
import matplotlib.pyplot as plt
|
||||
from rowingdata import rower as rrower
|
||||
|
||||
from rowingdata import main as rmain
|
||||
from rowingdata import rowingdata as rdata
|
||||
from rowingdata import TCXParser
|
||||
import StringIO
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
import django_rq
|
||||
queue = django_rq.get_queue('default')
|
||||
|
||||
import datetime
|
||||
import pandas as pd
|
||||
import os
|
||||
import numpy as np
|
||||
import json
|
||||
import mpld3
|
||||
|
||||
from rctasks import addrc
|
||||
|
||||
from rows import *
|
||||
from rowers.tasks import add as addtask
|
||||
from rowers.tasks import handle_makeplot
|
||||
from celery.result import AsyncResult
|
||||
from celery.exceptions import TimeoutError
|
||||
from rowers.models import Rower,User,Workout,GraphImage
|
||||
|
||||
|
||||
def showStaticImage(request,imagename):
|
||||
return render(request, 'image_page.html', {'imagename': imagename})
|
||||
|
||||
def rootview(request):
|
||||
magicsentence = rmain()
|
||||
return render(request, 'frontpage.html', {'versionstring': magicsentence})
|
||||
|
||||
|
||||
def version(request):
|
||||
magicsentence = rmain()
|
||||
return render(request, 'base.html', {'versionstring': magicsentence})
|
||||
|
||||
def rowingdata(request,formloc):
|
||||
if request.method == 'POST':
|
||||
form = DocumentsForm(request.POST,request.FILES)
|
||||
|
||||
if form.is_valid():
|
||||
f = request.FILES['file']
|
||||
t = request.POST['title']
|
||||
res = handle_uploaded_file(f)
|
||||
f1 = res[0]
|
||||
f2 = res[1]
|
||||
row = rdata(f2)
|
||||
fig1 = row.get_timeplot_erg(t)
|
||||
|
||||
canvas = FigureCanvasAgg(fig1)
|
||||
# response = HttpResponse(content_type='image/png')
|
||||
# canvas.print_png(response)
|
||||
imagename = f1+'.png'
|
||||
plt.savefig('static/plots/'+imagename,format='png')
|
||||
plt.close(fig1)
|
||||
response = render(request,'image_page.html',{'imagename':'plots/'+imagename})
|
||||
|
||||
else:
|
||||
response = HttpResponse("invalid form")
|
||||
|
||||
return response
|
||||
else:
|
||||
form = DocumentsForm()
|
||||
return render(request, 'document_form.html',
|
||||
{'form':form, 'formloc': formloc})
|
||||
|
||||
@login_required()
|
||||
def nrowingdata(request,formloc):
|
||||
if request.method == 'POST':
|
||||
form = DocumentsForm(request.POST,request.FILES)
|
||||
|
||||
if form.is_valid():
|
||||
f = request.FILES['file']
|
||||
res = handle_uploaded_file(f)
|
||||
t = request.POST['title']
|
||||
fileformat = request.POST['fileformat']
|
||||
workouttype = request.POST['workouttype']
|
||||
notes = request.POST['notes']
|
||||
|
||||
f1 = res[0] # file name
|
||||
f2 = res[1] # file name incl media directory
|
||||
|
||||
# handle TCX
|
||||
if (fileformat == 'tcx'):
|
||||
row = TCXParser(f2)
|
||||
f_to_be_deleted = f2
|
||||
# should delete file
|
||||
f2 = f2+'.csv'
|
||||
row.write_csv(f2)
|
||||
os.remove(f_to_be_deleted)
|
||||
|
||||
imagename = f1+'.png'
|
||||
fullpathimagename = 'static/plots/'+imagename
|
||||
u = request.user
|
||||
r = Rower.objects.get(user=request.user)
|
||||
hrdata = {
|
||||
'hrmax':r.max,
|
||||
'hrut2':r.ut2,
|
||||
'hrut1':r.ut1,
|
||||
'hrat':r.at,
|
||||
'hrtr':r.tr,
|
||||
'hran':r.an,
|
||||
}
|
||||
|
||||
# make plot - asynchronous task
|
||||
res = handle_makeplot.delay(f1,f2,t,hrdata)
|
||||
|
||||
# make workout and put in database
|
||||
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||
hrut1=r.ut1,hrat=r.at,
|
||||
hrtr=r.tr,hran=r.an)
|
||||
row = rdata(f2,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
|
||||
duration = "%s:%s:%s" % (hours,minutes,seconds)
|
||||
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
# check for duplicate start times
|
||||
r = Rower.objects.get(user=request.user)
|
||||
|
||||
ws = Workout.objects.filter(starttime=workoutstarttime,
|
||||
user=r)
|
||||
if (len(ws) != 0):
|
||||
print "Warning: This workout probably already exists in the database"
|
||||
|
||||
w = Workout(user=r,name=t,date=workoutdate,workouttype=workouttype,
|
||||
duration=duration,distance=totaldist,
|
||||
weightcategory=r.weightcategory,
|
||||
starttime=workoutstarttime,
|
||||
csvfilename=f2,notes=notes)
|
||||
w.save()
|
||||
|
||||
i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(),
|
||||
filename=fullpathimagename)
|
||||
i.save()
|
||||
|
||||
url = reverse(waitforplot,args=[str(res.id)])
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
else:
|
||||
response = HttpResponse("invalid form")
|
||||
|
||||
return response
|
||||
else:
|
||||
form = DocumentsForm()
|
||||
return render(request, 'document_form.html',
|
||||
{'form':form, 'formloc': formloc})
|
||||
|
||||
|
||||
|
||||
def uploadfile(request,formloc):
|
||||
if request.method == 'POST':
|
||||
form = DocumentsForm(request.POST, request.FILES)
|
||||
|
||||
if form.is_valid():
|
||||
result = handle_uploaded_file(request.FILES['file'])
|
||||
return HttpResponse("succes! "+result)
|
||||
else:
|
||||
return HttpResponse("Invalid Form")
|
||||
else:
|
||||
form = DocumentsForm()
|
||||
return render(request, 'document_form.html',
|
||||
{'form': form, 'formloc':formloc})
|
||||
|
||||
@login_required()
|
||||
def add(request,x,y):
|
||||
if settings.DEBUG:
|
||||
task = addtask.apply_async((int(x),int(y)),countdown=10)
|
||||
task_id = AsyncResult(task)
|
||||
print task.id
|
||||
else:
|
||||
task = queue.enqueue(addrc,x,y,0)
|
||||
task_id = task.id
|
||||
|
||||
url = reverse(wait,args=[str(task_id)])
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
|
||||
def wait(request,task_id=""):
|
||||
if settings.DEBUG:
|
||||
res = AsyncResult(task_id)
|
||||
else:
|
||||
res = queue.fetch_job(task_id)
|
||||
if (res.status == 'SUCCESS') or (res.status == 'finished'):
|
||||
return HttpResponse("Task complete. Result: "+str(res.result))
|
||||
else:
|
||||
m = "Task status: "+str(res.status)
|
||||
return render(request,'waiting_page.html',{'message':m})
|
||||
return HttpResponse("Task status: "+str(res.status)+". <p>Hit reload to check again")
|
||||
|
||||
|
||||
def waitforplot(request,task_id=""):
|
||||
res = AsyncResult(task_id)
|
||||
if (res.status == 'SUCCESS'):
|
||||
url = reverse(showplot,args=[str(res.result)])
|
||||
return HttpResponseRedirect(url)
|
||||
else:
|
||||
m = "Task status: "+str(res.status)
|
||||
|
||||
return render(request,'waiting_page.html',{'message':m})
|
||||
|
||||
def showplot(request,imagename=""):
|
||||
return render(request,'image_page.html',{'imagename':'plots/'+imagename})
|
||||
|
||||
|
||||
def contact(request):
|
||||
if request.method == 'POST':
|
||||
form = ContactForm(request.POST)
|
||||
if form.is_valid():
|
||||
cd = form.cleaned_data
|
||||
send_mail(
|
||||
cd['subject'],
|
||||
cd['message'],
|
||||
cd.get('email', 'noreply@example.com'),
|
||||
['siteowner@example.com'],
|
||||
)
|
||||
return HttpResponseRedirect('/contact/thanks/')
|
||||
else:
|
||||
form = ContactForm()
|
||||
return render(request, 'contact_form.html', {'form': form})
|
||||
|
||||
def interactiveplot(request):
|
||||
x = np.linspace(-10,10,num=1200)
|
||||
y = x**2-5*x+4
|
||||
fig = plt.figure(figsize=(6,5))
|
||||
graph = plt.plot(x,y)
|
||||
g = mpld3.fig_to_html(fig)
|
||||
# js_data = json.dumps(mpld3.fig_to_dict(fig))
|
||||
plt.close()
|
||||
# return render(request,'interactiveplot.html',{"my_data":js_data})
|
||||
return HttpResponse(g)
|
||||
|
||||
@@ -13,4 +13,4 @@ from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "rowsandall_app.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
application = get_wsgi_application()
|
||||
|
||||
Reference in New Issue
Block a user