Merge branch 'release/v4.64'
This commit is contained in:
@@ -3,6 +3,7 @@ from __future__ import absolute_import
|
||||
import os
|
||||
|
||||
from celery import Celery
|
||||
from celery import result
|
||||
|
||||
# Only used for testing with Celery on localhost. RQ is not available
|
||||
# on Windows, so I use Celery on my notebook.
|
||||
@@ -17,6 +18,7 @@ app = Celery('tasks',
|
||||
broker='redis://localhost',
|
||||
backend='redis://localhost',)
|
||||
|
||||
|
||||
class Config:
|
||||
CELERY_TIMEZONE = 'Europe/Prague'
|
||||
|
||||
@@ -31,3 +33,4 @@ database_url = 'sqlite:///db.sqlite3'
|
||||
@app.task(bind=True)
|
||||
def debug_task(self):
|
||||
print('Request: {0!r}'.format(self.request))
|
||||
|
||||
|
||||
+9
-6
@@ -473,9 +473,11 @@ def updatecpdata_sql(rower_id,delta,cp,table='cpdata',distance=[]):
|
||||
engine.dispose()
|
||||
|
||||
|
||||
def runcpupdate(rower,type='water'):
|
||||
startdate = timezone.now()-datetime.timedelta(days=365)
|
||||
enddate = timezone.now()+datetime.timedelta(days=5)
|
||||
def runcpupdate(
|
||||
rower,type='water',
|
||||
startdate=timezone.now()-datetime.timedelta(days=365),
|
||||
enddate=timezone.now()+datetime.timedelta(days=5)
|
||||
):
|
||||
if type == 'water':
|
||||
theworkouts = Workout.objects.filter(
|
||||
user=rower,rankingpiece=True,
|
||||
@@ -499,11 +501,12 @@ def runcpupdate(rower,type='water'):
|
||||
|
||||
theids = [w.id for w in theworkouts]
|
||||
|
||||
|
||||
if settings.DEBUG:
|
||||
res = handle_updatecp.delay(rower.id,theids,debug=True,table=table)
|
||||
job = handle_updatecp.delay(rower.id,theids,debug=True,table=table)
|
||||
else:
|
||||
res = queue.enqueue(handle_updatecp,rower.id,theids,table=table)
|
||||
job = queue.enqueue(handle_updatecp,rower.id,theids,table=table)
|
||||
|
||||
return job
|
||||
|
||||
def fetchcperg(rower,theworkouts):
|
||||
theids = [int(w.id) for w in theworkouts]
|
||||
|
||||
@@ -264,6 +264,15 @@ class Rower(models.Model):
|
||||
p3 = models.FloatField(default=1.0,verbose_name="CP p4")
|
||||
cpratio = models.FloatField(default=1.0,verbose_name="CP fit ratio")
|
||||
|
||||
|
||||
ep0 = models.FloatField(default=1.0,verbose_name="erg CP p1")
|
||||
ep1 = models.FloatField(default=1.0,verbose_name="erg CP p2")
|
||||
ep2 = models.FloatField(default=1.0,verbose_name="erg CP p3")
|
||||
ep3 = models.FloatField(default=1.0,verbose_name="erg CP p4")
|
||||
ecpratio = models.FloatField(default=1.0,verbose_name="erg CP fit ratio")
|
||||
|
||||
|
||||
|
||||
otwslack = models.IntegerField(default=0,verbose_name="OTW Power slack")
|
||||
|
||||
pw_ut2 = models.IntegerField(default=124,verbose_name="UT2 Power")
|
||||
|
||||
@@ -50,7 +50,11 @@
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_members %}
|
||||
{% if workouttype == 'water' %}
|
||||
<a class="button green small" href="/rowers/{{ member.id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">{{ member.first_name }} {{ member.last_name }}</a>
|
||||
{% else %}
|
||||
<a class="button green small" href="/rowers/{{ member.id }}/ote-ranking/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">{{ member.first_name }} {{ member.last_name }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
@@ -64,14 +68,22 @@
|
||||
between {{ startdate|date }} and {{ enddate|date }}</p>
|
||||
|
||||
<p>Direct link for other users:
|
||||
<a href="/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">https://rowsandall.com/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
|
||||
{% if workouttype == 'water' %}
|
||||
<a href="/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">https://rowsandall.com/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
|
||||
{% else %}
|
||||
<a href="/rowers/{{ id }}/ote-ranking/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">https://rowsandall.com/rowers/{{ id }}/ote-ranking/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<p>The table gives the OTW efforts you marked as Ranking Piece.
|
||||
<p>The table gives the efforts you marked as Ranking Piece.
|
||||
The graph shows the best segments from those pieces, plotted as
|
||||
average power (over the segment) vs the duration of the segment/
|
||||
In other words: How long you can hold that power.
|
||||
</p>
|
||||
|
||||
<p>When you change the date range, the algorithm calculates new
|
||||
parameters in a background process. You may have to reload the
|
||||
page to get an updated prediction.</p>
|
||||
<p>At the bottom of the page, you will find predictions derived from the model.</p>
|
||||
</div>
|
||||
<div id="form" class="grid_6 omega">
|
||||
|
||||
@@ -43,7 +43,16 @@
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="grid_2 suffix_8 omega">
|
||||
<div class="grid_2">
|
||||
{% if user.is_authenticated and user == rower.user %}
|
||||
<p>
|
||||
<a class="button gray small" href="/rowers/workout/{{ graph.workout.id }}/workflow">Workflow View</a>
|
||||
</p>
|
||||
{% else %}
|
||||
<p> </p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="grid_2 suffix_6 omega">
|
||||
{% if user.is_authenticated and user == rower.user %}
|
||||
<p>
|
||||
<a class="button red small" href="/rowers/graph/{{ graph.id }}/deleteconfirm">Delete Chart</a>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<p>On this page, you can configure the content of your "Workflow" page
|
||||
for each workout. If you want to remove an element, change it to "None".
|
||||
You can add one new element at a time.</p>
|
||||
<div class="grid_6 alpha">
|
||||
<div class="grid_4 alpha">
|
||||
<h2>Left Panel</h2>
|
||||
<form enctype="multipart/form-data" action="" method="post">
|
||||
{{ leftpanel_formset.management_form }}
|
||||
@@ -33,7 +33,7 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid_6 omega ">
|
||||
<div class="grid_4">
|
||||
<h2>Middle Panel</h2>
|
||||
<form enctype="multipart/form-data" action="" method="post">
|
||||
{{ middlepanel_formset.management_form }}
|
||||
@@ -45,6 +45,18 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid_4 omega">
|
||||
<div class="grid_2 prefix_2 alpha">
|
||||
{% if rower.defaultlandingpage == 'workout_edit_view' %}
|
||||
<p>Default landing page is Edit View. Set default landing page to</p>
|
||||
<a class="button green small" href="/rowers/me/workflowdefault">Workflow View</a>
|
||||
{% else %}
|
||||
<p>Default landing page is Workflow View. Set default landing page to</p>
|
||||
<a class="button green small" href="/rowers/me/workflowdefault">Edit View</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -320,6 +320,7 @@ urlpatterns = [
|
||||
url(r'^me/favoritecharts/$',views.rower_favoritecharts_view),
|
||||
url(r'^me/workflowconfig$',views.workout_workflow_config_view),
|
||||
url(r'^me/workflowconfig2$',views.workout_workflow_config2_view),
|
||||
url(r'^me/workflowdefault$',views.workflow_default_view),
|
||||
url(r'^email/send/$', views.sendmail),
|
||||
url(r'^email/thankyou/$', TemplateView.as_view(template_name='thankyou.html'), name='thankyou'),
|
||||
url(r'^email/$', TemplateView.as_view(template_name='email.html'), name='email'),
|
||||
|
||||
+127
-12
@@ -131,6 +131,16 @@ queue = django_rq.get_queue('default')
|
||||
queuelow = django_rq.get_queue('low')
|
||||
queuehigh = django_rq.get_queue('low')
|
||||
|
||||
from redis import StrictRedis
|
||||
from rq.exceptions import NoSuchJobError
|
||||
from rq.registry import StartedJobRegistry
|
||||
from rq import Queue
|
||||
|
||||
redis_connection = StrictRedis()
|
||||
rq_registry = StartedJobRegistry(queue.name,connection=redis_connection)
|
||||
|
||||
from rq.job import Job
|
||||
|
||||
from rest_framework_swagger.views import get_swagger_view
|
||||
from rest_framework.renderers import JSONRenderer
|
||||
from rest_framework.parsers import JSONParser
|
||||
@@ -155,10 +165,30 @@ from scipy.interpolate import griddata
|
||||
USER_LANGUAGE = 'en-US'
|
||||
|
||||
from interactiveplots import *
|
||||
from rowers.celery import result as celery_result
|
||||
|
||||
# Define the API documentation
|
||||
schema_view = get_swagger_view(title='Rowsandall API')
|
||||
|
||||
def get_job_result(jobid):
|
||||
if settings.DEBUG:
|
||||
result = celery_result.AsyncResult(jobid).result
|
||||
else:
|
||||
running_job_ids = rq_registry.get_job_ids()
|
||||
if len(running_job_ids) and jobid in running_job_ids:
|
||||
# job is running
|
||||
return None
|
||||
else:
|
||||
# job is ready
|
||||
try:
|
||||
job = Job.fetch(jobid,connection=redis_connection)
|
||||
result = job.result
|
||||
except NoSuchJobError:
|
||||
return None
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# Test if row data include candidates
|
||||
def rowhascoordinates(row):
|
||||
# create interactive plot
|
||||
@@ -3077,6 +3107,32 @@ def otwrankings_view(request,theuser=0,
|
||||
|
||||
delta,cpvalue,avgpower = dataprep.fetchcp(r,theworkouts)
|
||||
|
||||
runningjob = 0
|
||||
|
||||
try:
|
||||
jobid = request.session['job_id']
|
||||
if jobid:
|
||||
result = get_job_result(jobid)
|
||||
if result:
|
||||
messages.info(request,'Your calculation is ready')
|
||||
runningjob = 1
|
||||
request.session['job_id'] = 0
|
||||
else:
|
||||
runningjob = 1
|
||||
messages.info(request,'Your job is still running')
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
if not runningjob:
|
||||
job = dataprep.runcpupdate(
|
||||
r,type='water',
|
||||
startdate=startdate,
|
||||
enddate=enddate
|
||||
)
|
||||
request.session['job_id'] = job.id
|
||||
messages.info(request,'New calculation queued. Refresh page or resubmit the date form to get the result')
|
||||
|
||||
powerdf = pd.DataFrame({
|
||||
'Delta':delta,
|
||||
'CP':cpvalue,
|
||||
@@ -3181,6 +3237,7 @@ def otwrankings_view(request,theuser=0,
|
||||
'startdate':startdate,
|
||||
'enddate':enddate,
|
||||
'teams':get_my_teams(request.user),
|
||||
'workouttype':'water',
|
||||
})
|
||||
# Show ranking distances including predicted paces
|
||||
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
||||
@@ -3299,6 +3356,32 @@ def oterankings_view(request,theuser=0,
|
||||
r,theworkouts,table='cpergdata'
|
||||
)
|
||||
|
||||
runningjob = 0
|
||||
|
||||
try:
|
||||
jobid = request.session['job_id']
|
||||
if jobid:
|
||||
result = get_job_result(jobid)
|
||||
if result:
|
||||
messages.info(request,'Your calculation is ready')
|
||||
runningjob = 1
|
||||
request.session['job_id'] = 0
|
||||
else:
|
||||
runningjob = 1
|
||||
messages.info(request,'Your job is still running')
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
if not runningjob:
|
||||
job = dataprep.runcpupdate(
|
||||
r,type='rower',
|
||||
startdate=startdate,
|
||||
enddate=enddate
|
||||
)
|
||||
request.session['job_id'] = job.id
|
||||
messages.info(request,'New calculation queued. Refresh page or resubmit the date form to get the result')
|
||||
|
||||
powerdf = pd.DataFrame({
|
||||
'Delta':delta,
|
||||
'CP':cpvalue,
|
||||
@@ -3320,11 +3403,11 @@ def oterankings_view(request,theuser=0,
|
||||
div = res[1]
|
||||
p1 = res[2]
|
||||
ratio = res[3]
|
||||
r.p0 = p1[0]
|
||||
r.p1 = p1[1]
|
||||
r.p2 = p1[2]
|
||||
r.p3 = p1[3]
|
||||
r.cpratio = ratio
|
||||
r.ep0 = p1[0]
|
||||
r.ep1 = p1[1]
|
||||
r.ep2 = p1[2]
|
||||
r.ep3 = p1[3]
|
||||
r.ecpratio = ratio
|
||||
r.save()
|
||||
paulslope = 1
|
||||
paulintercept = 1
|
||||
@@ -3403,6 +3486,7 @@ def oterankings_view(request,theuser=0,
|
||||
'startdate':startdate,
|
||||
'enddate':enddate,
|
||||
'teams':get_my_teams(request.user),
|
||||
'workouttype':'rower',
|
||||
})
|
||||
|
||||
# Reload the workout and calculate the summary from the stroke data (lapIDx)
|
||||
@@ -5427,7 +5511,7 @@ def workout_otwsetpower_view(request,id=0,message="",successmessage=""):
|
||||
ratio=r.cpratio)
|
||||
else:
|
||||
res = queuelow.enqueue(handle_otwsetpower,f1,boattype,
|
||||
weightvalue,
|
||||
weightvalue,
|
||||
first_name,last_name,emailaddress,id,
|
||||
ps=[r.p0,r.p1,r.p2,r.p3],
|
||||
ratio=r.cpratio)
|
||||
@@ -6064,6 +6148,22 @@ def workout_comparison_view2(request,id1=0,id2=0,xparam='distance',
|
||||
'promember':promember,
|
||||
})
|
||||
|
||||
# Change default landing page
|
||||
@login_required()
|
||||
def workflow_default_view(request):
|
||||
r = getrower(request.user)
|
||||
if r.defaultlandingpage == 'workout_edit_view':
|
||||
r.defaultlandingpage = 'workout_workflow_view'
|
||||
else:
|
||||
r.defaultlandingpage = 'workout_edit_view'
|
||||
|
||||
r.save()
|
||||
|
||||
url = reverse(workout_workflow_config2_view)
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
# Workflow Configuration
|
||||
@login_required()
|
||||
def workout_workflow_config_view(request):
|
||||
@@ -6176,7 +6276,7 @@ def workout_workflow_config2_view(request):
|
||||
|
||||
return render(request,tmplt,
|
||||
{
|
||||
'rower':r,
|
||||
'rower':getrower(request.user),
|
||||
'leftpanel_formset':leftpanel_formset,
|
||||
'middlepanel_formset':middlepanel_formset,
|
||||
'workoutid': workoutid,
|
||||
@@ -6203,6 +6303,10 @@ def workout_workflow_view(request,id):
|
||||
if request.user == row.user.user:
|
||||
mayedit=1
|
||||
|
||||
comments = WorkoutComment.objects.filter(workout=row)
|
||||
|
||||
aantalcomments = len(comments)
|
||||
|
||||
workouttype = 'ote'
|
||||
if row.workouttype in ('water','coastal'):
|
||||
workouttype = 'otw'
|
||||
@@ -6264,6 +6368,7 @@ def workout_workflow_view(request,id):
|
||||
'mapdiv':mapdiv,
|
||||
'statcharts':statcharts,
|
||||
'rower':r,
|
||||
'aantalcomments':aantalcomments,
|
||||
})
|
||||
|
||||
# The famous flex chart
|
||||
@@ -7560,7 +7665,9 @@ def workout_getstravaworkout_view(request,stravaid):
|
||||
messages.error(request,message)
|
||||
|
||||
|
||||
url = reverse(workout_edit_view,
|
||||
r = getrower(request.user)
|
||||
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':int(id),
|
||||
})
|
||||
@@ -7581,7 +7688,9 @@ def workout_getrunkeeperworkout_view(request,runkeeperid):
|
||||
if message:
|
||||
messages.error(request,message)
|
||||
|
||||
url = reverse(workout_edit_view,
|
||||
r = getrower(request.user)
|
||||
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':int(id),
|
||||
})
|
||||
@@ -7600,7 +7709,9 @@ def workout_getunderarmourworkout_view(request,underarmourid):
|
||||
if message:
|
||||
messages.error(request,message)
|
||||
|
||||
url = reverse(workout_edit_view,
|
||||
r = getrower(request.user)
|
||||
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':int(id),
|
||||
})
|
||||
@@ -7625,7 +7736,9 @@ def workout_getsporttracksworkout_view(request,sporttracksid):
|
||||
if message:
|
||||
messages.error(request,message)
|
||||
|
||||
url = reverse(workout_edit_view,
|
||||
r = getrower(request.user)
|
||||
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':int(id),
|
||||
})
|
||||
@@ -7769,7 +7882,9 @@ def workout_getc2workout_view(request,c2id):
|
||||
if message:
|
||||
messages.error(request,message)
|
||||
|
||||
url = reverse(workout_edit_view,
|
||||
r = getrower(request.user)
|
||||
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':int(id),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user