Private
Public Access
1
0

shared sessions now work

This commit is contained in:
Sander Roosendaal
2021-03-05 11:52:56 +01:00
parent b107ea3a50
commit f88af509cc
7 changed files with 448 additions and 33 deletions

View File

@@ -2324,7 +2324,7 @@ class PlannedSession(models.Model):
interval_string = models.TextField(max_length=1000,default=None,blank=True,null=True,
verbose_name='Interval String (optional)')
tags = TaggableManager()
tags = TaggableManager(blank=True)
def __str__(self):

View File

@@ -101,9 +101,6 @@
</li>
<li class="grid_2">
<h1>Session Library</h1>
<p>
Click on session name to clone to current period
</p>
{% if alltags %}
<p>
Click on a tag to filter:
@@ -120,7 +117,7 @@
<tr>
<th>Name</th>
<th>Value</th>
<th>&nbsp;</th>
<th>Copy to Calendar</th>
<th>Edit</th>
<th>Delete</th>
</tr>
@@ -130,21 +127,28 @@
<tr>
<td>
{% if ps.name != '' %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/user/{{ rower.user.id }}/?when={{ timeperiod }}">{{ ps.name }}</a>
{{ ps.name }}
{% else %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/user/{{ rower.user.id }}/?when={{ timeperiod }}">Unnamed Session</a>
Unnamed Session
{% endif %}
</td>
<td> {{ ps.sessionvalue }} </td>
<td> {{ ps.sessionunit }} </td>
<td> {{ ps.sessionvalue }} {{ ps.sessionunit }} </td>
<td>
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/user/{{ rower.user.id }}/?when={{ timeperiod }}">
<i class="fas fa-clone fa-fw"></i>
</a>
</td>
{% if ps.manager == request.user %}
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/templateedit/"><i class="fas fa-pencil-alt fa-fw"></i></a>
</td>
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/deleteconfirm/?next={{ request.path|urlencode }}"><i class="fas fa-trash-alt fa-fw"></i></a>
</td>
{% else %}
<td></td><td></td>
{% endif %}
</tr>
{% endfor %}
</tbody>

View File

@@ -107,15 +107,23 @@
{% endif %}
<li class="grid_2">
<h1>Session Library</h1>
<p>
Click on session name to clone to current period
</p>
{% if alltags %}
<p>
Click on a tag to filter:
{% for tag in alltags %}
<a href="/rowers/sessions/create/?when={{ timeperiod }}&tag={{ tag }}">{{ tag }}</a>
{% endfor %}
</p>
<p>
<a href="/rowers/sessions/create/?when={{ timeperiod }}">Clear tags</a>
</p>
{% endif %}
<table class="listtable shortpadded" width="80%">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th>&nbsp;</th>
<th>Copy to Calendar</th>
<th>Edit</th>
<th>Delete</th>
</tr>
@@ -125,21 +133,28 @@
<tr>
<td>
{% if ps.name != '' %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/team/?when={{ timeperiod }}">{{ ps.name }}</a>
{{ ps.name }}
{% else %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/team/?when={{ timeperiod }}">Unnamed Session</a>
Unnamed Session
{% endif %}
</td>
<td> {{ ps.sessionvalue }} </td>
<td> {{ ps.sessionunit }} </td>
<td> {{ ps.sessionvalue }} {{ ps.sessionunit }} </td>
<td>
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/team/">
<i class="fas fa-clone fa-fw"></i>
</a>
</td>
{% if ps.manager == request.user %}
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/templateedit/"><i class="fas fa-pencil-alt fa-fw"></i></a>
</td>
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/deleteconfirm/"><i class="fas fa-trash-alt fa-fw"></i></a>
<a class="small" href="/rowers/sessions/{{ ps.id }}/deleteconfirm/?next={{ request.path|urlencode }}"><i class="fas fa-trash-alt fa-fw"></i></a>
</td>
{% else %}
<td></td><td></td>
{% endif %}
</tr>
{% endfor %}
</tbody>

View File

@@ -0,0 +1,194 @@
{% extends "newbase.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Create Library Session{% endblock %}
{% block main %}
<h1>Edit Session Template</h1>
<ul class="main-content">
<li class="grid_2">
<h2>Create New Library Session</h2>
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<p>
<table>
{{ form.as_table }}
</table>
</p>
{% csrf_token %}
<div id="id_guidance">
</div>
<input class="button"
type="submit" value="Save">
</form>
</li>
<li class="grid_2">
<h1>Library</h1>
<p>
Click on session name to clone to current period
</p>
<table class="listtable shortpadded" width="80%">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th>&nbsp;</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for ps in sessiontemplates %}
<tr>
<td>
{% if ps.name != '' %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/user/{{ rower.user.id }}/?when={{ timeperiod }}">{{ ps.name }}</a>
{% else %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/user/{{ rower.user.id }}/?when={{ timeperiod }}">Unnamed Session</a>
{% endif %}
</td>
<td> {{ ps.sessionvalue }} </td>
<td> {{ ps.sessionunit }} </td>
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/templateedit/"><i class="fas fa-pencil-alt fa-fw"></i> </a>
</td>
<td>
<a class="small" href="/rowers/sessions/{{ ps.id }}/deleteconfirm/"><i class="fas fa-trash-alt fa-fw"></i> </a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</li>
</ul>
{% endblock %}
{% block sidebar %}
{% include 'menu_plan.html' %}
{% endblock %}
{% block scripts %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
$(document).ready(function(){
var o = $("td #id_sessiontype").find(":selected").val();
if (o != 'coursetest') {
$("td #id_course").hide();
$("th label[for='id_course']").hide();
} else {
$("td #id_course").show();
$("th label[for='id_course']").show();
}
$("td #id_sessionmode").change(function() {
if (this.value == 'TRIMP') {
$("td #id_sessionunit").prop("value","None");
$('#id_guidance').html("<p>TRIMP has no unit</p>");
}
if (this.value == 'distance') {
$("td #id_sessionunit").prop("value","m");
$('#id_guidance').html("<p>Distance: Set value to meters</p>");
}
if (this.value == 'time') {
$("td #id_sessionunit").prop("value","min");
$('#id_guidance').html("<p>Time: Set value to minutes</p>");
}
if (this.value == 'rScore') {
$("td #id_sessionunit").prop("value","None");
$('#id_guidance').html("<p>rScore has no unit</p>");
}
});
$("td #id_sessiontype").change(function() {
if (this.value == 'session') {
$("td #id_criterium").prop("value","none");
$('#id_guidance').html("<p>For Training Sessions, the default criterium is 'Approximately'</p>");
}
if (this.value == 'test') {
$("td #id_criterium").prop("value","exact");
$("td #id_sessionmode").prop("value","distance");
$("td #id_sessionunit").prop("value","m");
$('#id_guidance').html("<p>Set mode to distance. For Mandatory Tests, only distance or time are allowed.</p><p>For Mandatory Tests, the only criterium is 'Exactly'</p>");
}
if (this.value == 'coursetest') {
$("th label[for='id_course']").show();
$("td #id_course").show();
$("td #id_criterium").prop("value","none");
$("td #id_sessionmode").prop("value","distance");
$("td #id_sessionunit").prop("value","m");
$('#id_guidance').html("<p>Set mode to distance. For OTW Tests, only distance is allowed.</p><p>The exact value is not relevant because it is calculated from the course.</p>");
}
if (this.value != 'coursetest') {
$("th label[for='id_course']").hide();
$("td #id_course").hide();
}
if (this.value == 'challenge') {
$("td #id_criterium").prop("value","minimum");
$('#id_guidance').html("<p>For Challenges, the default criterium is 'At Least'</p>");
}
if (this.value == 'cycletarget') {
$("td #id_criterium").prop("value","none");
$('#id_guidance').html("<p>For Cycle Targets, the default criterium is 'Approximately'</p>");
}
}
);
$("td #id_sessionunit").change(function() {
if (this.value == 'm') {
$("td #id_sessionmode").prop("value","distance");
$('#id_guidance').html("<p>Mode was set to distance</p>");
}
if (this.value == 'km') {
$("td #id_sessionmode").prop("value","distance");
$('#id_guidance').html("<p>Mode was set to distance</p>");
}
if (this.value == 'None') {
$("td #id_sessionmode").prop("value","rScore");
$('#id_guidance').html("<p>Mode was set to rScore</p>");
}
if (this.value == 'min') {
$("td #id_sessionmode").prop("value","time");
$('#id_guidance').html("<p>Mode was set to time</p>");
}
}
);
});
</script>
{% endblock %}

View File

@@ -8,11 +8,26 @@
<h1>Planned Session Library</h1>
{% if alltags %}
<p>
Click on a tag to filter:
{% for tag in alltags %}
<a href="/rowers/sessions/library/?tag={{ tag }}">{{ tag }}</a>
{% endfor %}
</p>
<p>
<a href="/rowers/sessions/library/">Clear tags</a>
</p>
{% endif %}
<ul class="main-content">
<li class="grid_4">
{% if templates %}
<p>
Click on session name to view, edit to change the session.
Sharing a session makes it available to all Rowsandall users on Self-Coach and Coach plans, so they can
use it in their own training plans. You can make the session private again at any time, but users
can save your session in their own private libraries.
</p>
<table width="90%" class="listtable shortpadded">
<thead>
@@ -20,8 +35,13 @@
<th align="left">Name</th>
<th align="left">Type</th>
<th align="left">Mode</th>
<th align="left">Value</th>
<th align="left">Private/Public</th>
<th align="left">Edit</th>
<th align="left">
<th align="left">Copy to Calendar</th>
<th align="left">Share</th>
<th align="left">Make Private</th>
<th align="left">Delete</th>
</tr>
</thead>
<tbody>
@@ -29,23 +49,56 @@
<tr>
<td>
{% if ps.name != '' %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/user/{{ rower.user.id }}">{{ ps.name }}</a>
{{ ps.name }}
{% else %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/user/{{ rower.user.id }}">Unnamed Session</a>
Unnamed Session
{% endif %}
</td>
<td> {{ ps.get_sessiontype_display }} </td>
<td> {{ ps.get_sessionmode_display }} </td>
<td> {{ ps.sessionvalue }} {{ ps.sessionunit }}</td>
<td>
{% if ps.is_public %}
<i class="fas fa-lock-open-alt"></i>
{% else %}
<i class="fas fa-lock-alt"></i>
{% endif %}
</td>
<td>
{% if ps.manager == request.user %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/templateedit/user/{{ rower.user.id }}">
<i class="fas fa-pencil-alt fa-fw"></i>
</a>
{% endif %}
</td>
<td>
<a class="small"
href="/rowers/sessions/{{ ps.id }}/clone/user/{{ rower.user.id }}">
<i class="fas fa-clone fa-fw"></i>
</a>
</td>
<td>
{% if ps.manager == request.user %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/share/">
<i class="fas fa-share-alt-square fa-fw"></i>
</a>
{% endif %}
</td>
<td>
{% if ps.manager == request.user %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/makeprivate/">
<i class="fas fa-lock fa-fw"></i>
</a>
{% endif %}
</td>
<td>
{% if ps.manager == request.user %}
<a class="small" href="/rowers/sessions/{{ ps.id }}/deleteconfirm/?next={{ request.path|urlencode }}"><i class="fas fa-trash-alt fa-fw"></i></a>
{% endif %}
</td>
<td> {{ ps.sessionvalue }} </td>
<td> {{ ps.sessionunit }} </td>
</tr>
{% endfor %}
</tbody>
@@ -55,6 +108,9 @@
{% endif %}
</li>
<li class="grid_4">
<a href="/rowers/sessions/createtemplate/">Add a session to the library</a>
</li>
</ul>

View File

@@ -806,11 +806,17 @@ urlpatterns = [
name='plannedsession_teamcreate_view'),
re_path(r'^sessions/teamedit/(?P<id>\d+)/$',views.plannedsession_teamedit_view,
name='plannedsession_teamedit_view'),
re_path(r'^sessions/(?P<id>\d+)/share/$',views.template_share_view,
name='template_share_view'),
re_path(r'^sessions/(?P<id>\d+)/makeprivate/$',views.template_makeprivate_view,
name='template_makeprivate_view'),
re_path(r'^sessions/teamedit/(?P<id>\d+)/user/(?P<userid>\d+)/$',
views.plannedsession_teamedit_view,
name='plannedsession_teamedit_view'),
re_path(r'^sessions/create/$',views.plannedsession_create_view,
name='plannedsession_create_view'),
re_path(r'^sessions/createtemplate/$',views.plannedsession_createtemplate_view,
name='plannedsession_createtemplate_view'),
re_path(r'^sessions/create/user/(?P<userid>\d+)/$',
views.plannedsession_create_view,
name='plannedsession_create_view'),

View File

@@ -412,6 +412,30 @@ def plannedsession_multiclone_view(
}
)
@permission_required('plannedsession.change_session',fn=get_session_by_pk,raise_exception=True)
@user_passes_test(can_plan,login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def template_share_view(request,id=0,userid=0):
r = getrequestplanrower(request,userid=userid)
ps = get_object_or_404(PlannedSession,pk=id)
ps.is_public = True
ps.save()
return HttpResponseRedirect(reverse(template_library_view))
@permission_required('plannedsession.change_session',fn=get_session_by_pk,raise_exception=True)
@user_passes_test(can_plan,login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def template_makeprivate_view(request,id=0,userid=0):
r = getrequestplanrower(request,userid=userid)
ps = get_object_or_404(PlannedSession,pk=id)
ps.is_public = False
ps.save()
return HttpResponseRedirect(reverse(template_library_view))
# Manage Template sessions (library)
@user_passes_test(can_plan,login_url="/rowers/paidplans/",
@@ -420,6 +444,9 @@ def plannedsession_multiclone_view(
def template_library_view(request,userid=0):
r = getrequestplanrower(request,userid=userid)
templates = PlannedSession.objects.filter(manager=request.user,is_template=True)
templates2 = PlannedSession.objects.filter(is_template=True,is_public=True)
templates = templates | templates2
startdate,enddate = get_dates_timeperiod(request)
@@ -431,6 +458,20 @@ def template_library_view(request,userid=0):
except IndexError:
trainingplan = None
alltags = []
for t in templates:
tags = t.tags.all()
for tag in tags:
alltags.append(tag)
alltags = uniqify(alltags)
tag = request.GET.get('tag')
if tag:
tags = [tag]
templates = templates.filter(tags__name__in=tags).distinct()
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
@@ -450,6 +491,7 @@ def template_library_view(request,userid=0):
'plan': trainingplan,
'rower':r,
'active':'nav-plan',
'alltags':alltags,
}
)
@@ -561,13 +603,19 @@ def plannedsession_create_view(request,
sessiontemplates = sessiontemplates.order_by("name")
alltags = []
for t in sessiontemplates:
tags = t.tags.all()
for tag in tags:
alltags.append(tag)
alltags = uniqify(alltags)
tag = request.GET.get('tag')
if tag:
tags = [tag]
sessiontemplates = sessiontemplates.filter(tags__name__in=tags).distinct()
alltags = Tag.objects.all()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
@@ -597,6 +645,84 @@ def plannedsession_create_view(request,
'alltags':alltags,
})
@user_passes_test(can_plan,login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_createtemplate_view(request,
userid=0,
):
r = getrequestplanrower(request,userid=userid)
startdate,enddate = get_dates_timeperiod(request)
if request.method == 'POST':
sessioncreateform = PlannedSessionTemplateForm(request.POST, request.FILES)
if sessioncreateform.is_valid():
ps = sessioncreateform.save(commit=False)
ps.manager = request.user
ps.is_template = True
ps.save()
sessioncreateform.save_m2m()
add_rower_session(r,ps)
url = reverse("template_library_view")
return HttpResponseRedirect(url)
else:
sessioncreateform = PlannedSessionTemplateForm()
sessiontemplates = PlannedSession.objects.filter(
manager=request.user,
is_template=True).order_by("name")
sessiontemplates2 = PlannedSession.objects.filter(
is_template=True,is_public=True
).order_by("name")
sessiontemplates = sessiontemplates | sessiontemplates2
sessiontemplates = sessiontemplates.order_by("name")
alltags = []
for t in sessiontemplates:
tags = t.tags.all()
for tag in tags:
alltags.append(tag)
alltags = uniqify(alltags)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rowers = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Sessions'
},
{
'url':reverse(plannedsession_createtemplate_view),
'name': 'Create Library Session'
}
]
return render(request,'plannedsessiontemplatecreate.html',
{
'teams':get_my_teams(request.user),
'plan':trainingplan,
'form':sessioncreateform,
'active':'nav-plan',
'rower':r,
'alltags':alltags,
})
@user_passes_test(can_plan,login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
@@ -767,6 +893,8 @@ def plannedsession_teamcreate_view(request,
"preferreddate","startdate","enddate")
sessiontemplates = PlannedSession.objects.filter(manager=request.user,is_template=True)
sessiontemplates2 = PlannedSession.objects.filter(is_template=True,is_public=True)
sessiontemplates = sessiontemplates | sessiontemplates2
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(request.POST, request.FILES)
@@ -1668,7 +1796,9 @@ def plannedsession_templateedit_view(request,id=0):
elif cd['sessionunit'] in ['km','m']:
cd['sessionmode'] = 'distance'
obj = sessioncreateform.save()
obj = sessioncreateform.save(commit=False)
obj.save()
sessioncreateform.save_m2m()
res, message = update_plannedsession(ps,cd)
#sessioncreateform.save_m2m()
@@ -1705,6 +1835,11 @@ def plannedsession_templateedit_view(request,id=0):
]
sessiontemplates = PlannedSession.objects.filter(manager=request.user,is_template=True)
sessiontemplates2 = PlannedSession.objects.filter(
is_template=True,is_public=True
).order_by("name")
sessiontemplates = sessiontemplates | sessiontemplates2
return render(request,'plannedsessiontemplateedit.html',
{
@@ -1848,6 +1983,11 @@ def plannedsession_edit_view(request,id=0,userid=0):
sessiontemplates = PlannedSession.objects.filter(manager=request.user,is_template=True)
sessiontemplates2 = PlannedSession.objects.filter(
is_template=True,is_public=True
).order_by("name")
sessiontemplates = sessiontemplates | sessiontemplates2
dateform = DateRangeForm(initial={
'startdate':startdate,