Merge branch 'release/v12.02'
This commit is contained in:
@@ -3730,3 +3730,16 @@ class VideoAnalysis(models.Model):
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
|
||||
class ShareKey(models.Model):
|
||||
location = models.TextField() # absolute path
|
||||
token = models.CharField(max_length=40, primary_key=True)
|
||||
creation_date = models.DateTimeField(auto_now_add=True)
|
||||
expiration_seconds = models.BigIntegerField()
|
||||
|
||||
|
||||
@property
|
||||
def expired(self):
|
||||
return self.creation_date + datetime.timedelta(self.expiration_seconds) < timezone.now()
|
||||
|
||||
@@ -713,8 +713,10 @@ def get_dates_timeperiod(request,startdatestring='',enddatestring='',
|
||||
if not timeperiod:
|
||||
timeperiod = defaulttimeperiod
|
||||
|
||||
startdatestring = request.GET.get('startdate')
|
||||
enddatestring = request.GET.get('enddate')
|
||||
if startdatestring == '':
|
||||
startdatestring = request.GET.get('startdate')
|
||||
if enddatestring == '':
|
||||
enddatestring = request.GET.get('enddate')
|
||||
|
||||
if startdatestring and enddatestring:
|
||||
try:
|
||||
|
||||
@@ -195,6 +195,9 @@ def can_add_session(user):
|
||||
|
||||
@rules.predicate
|
||||
def can_plan(user):
|
||||
if user.is_anonymous:
|
||||
return False
|
||||
|
||||
return user.rower.rowerplan in ['plan','coach','freecoach']
|
||||
|
||||
# checks if rower is coach of user (or is user himself)
|
||||
|
||||
@@ -37,8 +37,15 @@
|
||||
</table>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
<form enctype="multipart/form-data" action="/rowers/access/share/" method="post">
|
||||
{% csrf_token %}
|
||||
<input name="url" value="{{ request.path }}{{ timeperiod }}/" type="hidden">
|
||||
<label for="id_ndays">Number of days link is valid:</label>
|
||||
<input name="ndays" id="id_ndays" type="number" step="1" value="7">
|
||||
<input type="submit" value="create shareable link">
|
||||
</form>
|
||||
</p>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
42
rowers/templates/share.html
Normal file
42
rowers/templates/share.html
Normal file
@@ -0,0 +1,42 @@
|
||||
{% extends "newbase.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
{% load leaflet_tags %}
|
||||
|
||||
{% block meta %}
|
||||
{% leaflet_js %}
|
||||
{% leaflet_css %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}Share Page{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{% include "monitorjobs.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block og_title %}{{ race.name }}{% endblock %}
|
||||
{% block description %}Virtual Rowing Race {{ race.name }}{% endblock %}
|
||||
|
||||
{% if racelogo %}
|
||||
{% block og_image %}
|
||||
<meta property="og:image" content="http://rowsandall.com/{{ racelogo.filename|spacetohtml }}" />
|
||||
<meta property="og:image:secure_url" content="https://rowsandall.com/{{ racelogo.filename |spacetohtml }}" />
|
||||
<meta property="og:image:width" content="{{ racelogo.width }}" />
|
||||
<meta property="og:image:height" content="{{ racelogo.height }}" />
|
||||
{% endblock %}
|
||||
{% block image_src %}
|
||||
<link rel="image_src" href="/{{ racelogo.filename |spacetohtml }}" />
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
|
||||
<h1>Sharing link created.</h1>
|
||||
<p>The link is <a href="{{ base_url }}{% url 'sharedPage' key.pk %}">{{ base_url }}{% url 'sharedPage' key.pk %}</a>. It will be valid until {{ key.expiration_date|date:"l, N dS" }} at {{ key.expiration_date|time:"g:i a" }}.</p>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% include 'menu_racing.html' %}
|
||||
{% endblock %}
|
||||
@@ -56,6 +56,13 @@ def sigdig(value, digits = 3):
|
||||
fmtstr = "%.0f"
|
||||
return fmtstr % (round(value, places))
|
||||
|
||||
@register.filter
|
||||
def pickle(dc):
|
||||
s = dict()
|
||||
for key, value in dc.items():
|
||||
s[key] = value
|
||||
|
||||
return s
|
||||
|
||||
@register.filter(is_safe=True, needs_autoescape=True)
|
||||
@stringfilter
|
||||
|
||||
@@ -721,6 +721,8 @@ urlpatterns = [
|
||||
name='plannedsession_comment_view'),
|
||||
re_path(r'^sessions/print/user/(?P<userid>\d+)/$',views.plannedsessions_print_view,
|
||||
name='plannedsessions_print_view'),
|
||||
re_path(r'^sessions/print/user/(?P<userid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.plannedsessions_print_view,
|
||||
name='plannedsessions_print_view'),
|
||||
re_path(r'^sessions/sendcalendar/$',views.plannedsessions_icsemail_view,
|
||||
name='plannedsessions_coach_icsemail_view'),
|
||||
re_path(r'^sessions/sendcalendar/user/(?P<userid>\d+)/$',views.plannedsessions_icsemail_view,
|
||||
@@ -747,6 +749,8 @@ urlpatterns = [
|
||||
# URLS to be created
|
||||
re_path(r'^help/$',TemplateView.as_view(template_name='help.html'), name='help'),
|
||||
re_path(r'^workout/api/upload/',views.workout_upload_api,name='workout_upload_api'),
|
||||
re_path(r'^access/share/$',views.createShareURL, name="sharedURL"),
|
||||
re_path(r'^access/(?P<key>\w+)/$', views.sharedPage, name="sharedPage"),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
|
||||
@@ -319,7 +319,10 @@ def trendflexdata(workouts, options,userid=0):
|
||||
|
||||
today = datetime.date.today()
|
||||
|
||||
datadf['days ago'] = list(map(lambda x : x.days, datadf.date - today))
|
||||
try:
|
||||
datadf['days ago'] = list(map(lambda x : x.days, datadf.date - today))
|
||||
except TypeError:
|
||||
datadf['days ago'] = 0
|
||||
|
||||
|
||||
if groupby != 'date':
|
||||
|
||||
@@ -1183,14 +1183,16 @@ def plannedsessions_view(request,
|
||||
'unmatchedworkouts':unmatchedworkouts,
|
||||
})
|
||||
|
||||
@login_required()
|
||||
def plannedsessions_print_view(request,userid=0):
|
||||
@allow_shares
|
||||
#@login_required()
|
||||
def plannedsessions_print_view(request,userid=0,startdatestring='',enddatestring=''):
|
||||
|
||||
r = getrequestplanrower(request,userid=userid)
|
||||
|
||||
|
||||
|
||||
startdate,enddate = get_dates_timeperiod(request)
|
||||
startdate,enddate = get_dates_timeperiod(request,startdatestring=startdatestring,
|
||||
enddatestring=enddatestring)
|
||||
|
||||
try:
|
||||
trainingplan = TrainingPlan.objects.filter(
|
||||
|
||||
@@ -83,6 +83,7 @@ from django.core.exceptions import PermissionDenied
|
||||
from django.template import RequestContext
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from django.conf import settings
|
||||
from django.urls import resolve
|
||||
from django.utils.datastructures import MultiValueDictKeyError
|
||||
from django.utils import timezone,translation
|
||||
from django.core.mail import send_mail, BadHeaderError
|
||||
@@ -112,7 +113,7 @@ from rowers.models import (
|
||||
RaceLogo,RowerBillingAddressForm,PaidPlan,
|
||||
AlertEditForm, ConditionEditForm,
|
||||
PlannedSessionComment,CoachRequest,CoachOffer,
|
||||
VideoAnalysis
|
||||
VideoAnalysis,ShareKey,
|
||||
)
|
||||
from rowers.models import (
|
||||
RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
|
||||
@@ -251,11 +252,62 @@ from rq.exceptions import NoSuchJobError
|
||||
from rq.registry import StartedJobRegistry
|
||||
from rq import Queue,cancel_job
|
||||
|
||||
from django.utils.crypto import get_random_string
|
||||
|
||||
from django.core.cache import cache
|
||||
from django_mailbox.models import Message,Mailbox,MessageAttachment
|
||||
|
||||
from rules.contrib.views import permission_required, objectgetter
|
||||
|
||||
# creating shareable views
|
||||
def allow_shares(view_func):
|
||||
def sharify(request, *args, **kwargs):
|
||||
shared = kwargs.get('__shared', None)
|
||||
if shared is not None:
|
||||
del kwargs["__shared"]
|
||||
request.session['shared'] = True
|
||||
return view_func(request, *args, **kwargs)
|
||||
else: return login_required(view_func)(request, *args, **kwargs)
|
||||
return sharify
|
||||
|
||||
class SharifyError(Exception):
|
||||
pass
|
||||
|
||||
def sharedPage(request, key):
|
||||
try:
|
||||
try:
|
||||
shareKey = ShareKey.objects.get(pk=key)
|
||||
except:
|
||||
raise SharifyError
|
||||
if shareKey.expired:
|
||||
raise SharifyError
|
||||
func, args, kwargs = resolve(shareKey.location)
|
||||
kwargs["__shared"] = True
|
||||
return func(request, *args, **kwargs)
|
||||
except SharifyError:
|
||||
raise Http404 # or add a more detailed error page. This either means that the key doesn’t exist or is expired.
|
||||
|
||||
def createShareURL(request):
|
||||
if request.method == 'POST':
|
||||
url = request.POST['url']
|
||||
ndays = int(request.POST['ndays'])
|
||||
key = ShareKey.objects.create(pk=get_random_string(40),
|
||||
expiration_seconds=60*60*24*ndays,
|
||||
location = url)
|
||||
key.save()
|
||||
return render(request, 'share.html', {"key":key})
|
||||
else:
|
||||
raise Http404
|
||||
|
||||
def createShareModel(request, model_id):
|
||||
task = MyModel.objects.get(pk=model_id)
|
||||
key = ShareKey.objects.create(pk=get_random_string(40),
|
||||
expiration_seconds=60*60*24, # 1 day
|
||||
location = task.get_absolute_url(),
|
||||
)
|
||||
key.save()
|
||||
return render(request, 'share.html', {"key":key})
|
||||
|
||||
# Utility to get stroke data in a JSON response
|
||||
class JSONResponse(HttpResponse):
|
||||
def __init__(self, data, **kwargs):
|
||||
@@ -439,6 +491,9 @@ def getrequestplanrower(request,rowerid=0,userid=0,notpermanent=False):
|
||||
except Rower.DoesNotExist:
|
||||
raise Http404("Rower doesn't exist")
|
||||
|
||||
if 'shared' in request.session and request.session['shared']:
|
||||
return r
|
||||
|
||||
if r.user != request.user and not can_plan_user(request.user,r ):
|
||||
request.session['rowerid'] = r.id
|
||||
raise PermissionDenied("You have no access to this user")
|
||||
|
||||
Reference in New Issue
Block a user