adding poll for next week sessions
This commit is contained in:
@@ -37,6 +37,19 @@ formaxlabels = axlabels.copy()
|
||||
formaxlabels.pop('None')
|
||||
parchoices = list(sorted(formaxlabels.items(), key=lambda x: x[1]))
|
||||
|
||||
class DeepWaterLoginForm(forms.Form):
|
||||
username = forms.CharField(
|
||||
max_length=150, label='Username',
|
||||
widget=forms.TextInput(attrs={'placeholder': 'Username'}))
|
||||
password = forms.CharField(
|
||||
max_length=128, label='Password',
|
||||
widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(DeepWaterLoginForm, self).clean()
|
||||
if not cleaned_data.get('username') or not cleaned_data.get('password'):
|
||||
raise forms.ValidationError("Please enter both username and password.")
|
||||
return cleaned_data
|
||||
|
||||
class SurveyForm(forms.Form):
|
||||
surveydone = forms.ChoiceField(
|
||||
|
||||
44
rowers/management/commands/loadnextweeksessions.py
Normal file
44
rowers/management/commands/loadnextweeksessions.py
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/srv/venv/bin/python
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from rowers.models import Rower
|
||||
from rowers.tasks import handle_loadnextweek
|
||||
from rowers.utils import myqueue, dologging
|
||||
|
||||
import django_rq
|
||||
|
||||
PY3K = sys.version_info >= (3, 0)
|
||||
|
||||
queue = django_rq.get_queue('default')
|
||||
queuelow = django_rq.get_queue('low')
|
||||
queuehigh = django_rq.get_queue('low')
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--testing',
|
||||
action='store_true',
|
||||
dest='testing',
|
||||
default=False,
|
||||
help="Run in testing mode, don't send emails", )
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if 'testing' in options:
|
||||
testing = options['testing']
|
||||
else:
|
||||
testing = False
|
||||
|
||||
rowers = Rower.objects.filter(training_plan_code__isnull=False).exclude(training_plan_code__exact='')
|
||||
rowers = rowers.filter(training_plan_secret__isnull=False).exclude(training_plan_secret__exact='')
|
||||
|
||||
for rower in rowers:
|
||||
_ = myqueue(queue, handle_loadnextweek,
|
||||
rower)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
'Successfully loaded next week plans'
|
||||
))
|
||||
101
rowers/tasks.py
101
rowers/tasks.py
@@ -18,6 +18,7 @@ from rowers.models import (
|
||||
GraphImage, Team, PlannedSession
|
||||
)
|
||||
from rowers.session_utils import is_session_complete
|
||||
|
||||
import math
|
||||
from rowers.courseutils import (
|
||||
coursetime_paths, coursetime_first, time_in_path,
|
||||
@@ -333,6 +334,106 @@ def summaryfromsplitdata(splitdata, data, filename, sep='|', workouttype='rower'
|
||||
|
||||
return sums, sa, results
|
||||
|
||||
from rowers.utils import intensitymap
|
||||
|
||||
def strcapitalize(s):
|
||||
if s is None:
|
||||
return None
|
||||
if isinstance(s, str):
|
||||
return s[0].upper() + s[1:]
|
||||
|
||||
return s
|
||||
|
||||
def correct_intensity(workout):
|
||||
# reads the steps and if the intensity is an integer, converts it to a string
|
||||
steps = workout['steps']
|
||||
for step in steps:
|
||||
if 'intensity' in step:
|
||||
if isinstance(step['intensity'], int):
|
||||
step['intensity'] = intensitymap[step['intensity']]
|
||||
step['durationType'] = strcapitalize(step['durationType'])
|
||||
step['targetType'] = strcapitalize(step['targetType'])
|
||||
step['intensity'] = strcapitalize(step['intensity'])
|
||||
|
||||
return workout
|
||||
|
||||
|
||||
@app.task
|
||||
def handle_loadnextweek(rower, debug=False, **kwargs):
|
||||
|
||||
plan = rower.training_plan_code
|
||||
secret = rower.training_plan_secret
|
||||
post_data = {
|
||||
'fitness': rower.actualfit,
|
||||
'fatigue': rower.actualfatigue,
|
||||
'plan': plan,
|
||||
'secret': secret,
|
||||
}
|
||||
|
||||
url = "http://localhost:8898/next-week-plan/"
|
||||
response = requests.post(url, data=post_data)
|
||||
|
||||
if response.status_code in [200, 201]:
|
||||
data = response.json()
|
||||
|
||||
today = timezone.now()
|
||||
startdate = today - timedelta(days=today.weekday())+timezone.timedelta(days=7)
|
||||
enddate = startdate + timedelta(days=6)
|
||||
|
||||
sps = PlannedSession.objects.filter(
|
||||
rower__in=[rower],
|
||||
startdate__gte=startdate,
|
||||
enddate__lte=enddate,
|
||||
is_template=False,
|
||||
)
|
||||
|
||||
for ps in sps:
|
||||
ps.delete()
|
||||
|
||||
trainingdays = data['cycles']
|
||||
# start date is the first day of the following week
|
||||
|
||||
ndays = 0
|
||||
for day in trainingdays:
|
||||
try:
|
||||
workouts = day[0][1:]
|
||||
except IndexError:
|
||||
workouts =[]
|
||||
for workout in workouts:
|
||||
sessionsport = 'water'
|
||||
try:
|
||||
sessionsport = mytypes.fitmappinginv[workout['sport'].lower()]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
preferreddate = startdate+timedelta(days=ndays)
|
||||
sessionmode = 'time'
|
||||
|
||||
ps = PlannedSession(
|
||||
startdate=preferreddate - timedelta(days=preferreddate.weekday()),
|
||||
enddate=preferreddate + timedelta(days=-preferreddate.weekday()-1, weeks=1),
|
||||
preferreddate=preferreddate,
|
||||
sessionsport=sessionsport, # change this
|
||||
name=workout['workoutName'],
|
||||
steps=correct_intensity(workout),
|
||||
manager=rower.user,
|
||||
sessionmode=sessionmode,
|
||||
comment=workout['description'],
|
||||
from_plan=None,
|
||||
)
|
||||
ps.save()
|
||||
ps.rower.add(rower)
|
||||
ps.save()
|
||||
if ps.fitfile:
|
||||
ps.steps = {}
|
||||
ps.save()
|
||||
ndays += 1
|
||||
|
||||
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
@app.task
|
||||
def handle_assignworkouts(workouts, rowers, remove_workout, debug=False, **kwargs):
|
||||
for workout in workouts:
|
||||
|
||||
32
rowers/templates/deepwaterlogin.html
Normal file
32
rowers/templates/deepwaterlogin.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{% extends "newbase.html" %}
|
||||
{% load static %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}Login to Deep Water{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<h1>Login to Deep Water</h1>
|
||||
|
||||
<!-- clack_login.html -->
|
||||
<form method="post"{% if redirect_url %}?redirect={{ redirect_url|urlencode }}{% endif %}>
|
||||
{% csrf_token %}
|
||||
{% if error %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endif %}
|
||||
|
||||
<div>
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" id="username" name="username" required>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
||||
import six
|
||||
|
||||
import hmac, hashlib, base64, json, time
|
||||
|
||||
class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
|
||||
def _make_hash_value(self, user, timestamp):
|
||||
@@ -9,5 +9,15 @@ class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
|
||||
six.text_type(user.is_active)
|
||||
)
|
||||
|
||||
# Function to create a custom token for user authentication
|
||||
def create_token(user_id, username=None, secret_key="your-very-secret-key-here-change-this!"):
|
||||
expires = int(time.time()) + (24 * 3600) # 24 hours
|
||||
payload = json.dumps({"user_id": user_id, "username": username, "expires": expires})
|
||||
encoded_payload = base64.b64encode(payload.encode()).decode()
|
||||
signature = base64.b64encode(
|
||||
hmac.new(secret_key.encode(), encoded_payload.encode(), hashlib.sha256).digest()
|
||||
).decode()
|
||||
return f"{encoded_payload}.{signature}"
|
||||
|
||||
|
||||
account_activation_token = AccountActivationTokenGenerator()
|
||||
|
||||
@@ -1115,5 +1115,9 @@ urlpatterns = [
|
||||
name='nextweekplan_view'),
|
||||
re_path(r'^currentweekplan/$', views.currentweekplan_view,
|
||||
name='currentweekplan_view'),
|
||||
re_path(r'^deepwaterlogin/$', views.deepwatertoken_login,
|
||||
name='deepwatertoken_login'),
|
||||
re_path(r'^deepwatertoken/$', views.get_deepwater_token,
|
||||
name='get_deepwater_token'),
|
||||
]
|
||||
|
||||
|
||||
@@ -1,5 +1,51 @@
|
||||
from rowers.views.statements import *
|
||||
from rowers.rower_rules import user_is_not_basic, user_is_coachee
|
||||
from rowers.tokens import create_token
|
||||
from rowers.forms import DeepWaterLoginForm
|
||||
import jwt
|
||||
|
||||
def deepwatertoken_login(request):
|
||||
if request.method == 'POST':
|
||||
username = request.POST.get('username', '')
|
||||
password = request.POST.get('password', '')
|
||||
user = authenticate(request, username=username, password=password)
|
||||
if user is not None:
|
||||
login(request, user)
|
||||
payload = {
|
||||
'user_id': user.id,
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
'exp': timezone.now() + datetime.timedelta(days=1), # Token valid for 1 day
|
||||
'iat': timezone.now(),
|
||||
}
|
||||
|
||||
token = jwt.encode(payload, settings.DEEP_WATER_SECRET_KEY, algorithm='HS256')
|
||||
|
||||
# Debug: Print the token
|
||||
print(f"Generated token: {token}")
|
||||
print(f"Token length: {len(token)}")
|
||||
print(f"Token parts: {token.split('.')}")
|
||||
|
||||
redirect_url = request.GET.get('redirect', settings.DEEP_WATER_URL)
|
||||
return HttpResponseRedirect(f"{redirect_url}?token={token}")
|
||||
else:
|
||||
messages.error(request, 'Invalid credentials')
|
||||
return render(request, 'deepwaterlogin.html')
|
||||
redirect_url = request.GET.get('redirect', settings.DEEP_WATER_URL)
|
||||
return render(request, "deepwaterlogin.html")
|
||||
|
||||
@login_required()
|
||||
def get_deepwater_token(request):
|
||||
payload = {
|
||||
'user_id': request.user.id,
|
||||
'username': request.user.username,
|
||||
'email': request.user.email,
|
||||
'exp': timezone.now() + datetime.timedelta(days=1), # Token valid for 1 day
|
||||
'iat': timezone.now(),
|
||||
}
|
||||
|
||||
token = jwt.encode(payload, settings.DEEP_WATER_SECRET_KEY, algorithm='HS256')
|
||||
return JsonResponse({'token': token})
|
||||
|
||||
@login_required()
|
||||
def deactivate_user(request):
|
||||
|
||||
@@ -31,7 +31,8 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = CFG['secret_key']
|
||||
|
||||
DEEP_WATER_SECRET_KEY = CFG['deep_water_secret_key']
|
||||
DEEP_WATER_URL = CFG['deep_water_url']
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
||||
Reference in New Issue
Block a user