Private
Public Access
1
0

medium level and account page

This commit is contained in:
Sander Roosendaal
2017-02-09 12:23:56 +01:00
parent 0969399e36
commit f393862a92
6 changed files with 311 additions and 145 deletions

View File

@@ -11,6 +11,7 @@ from datetimewidget.widgets import DateTimeWidget
from django.core.validators import validate_email
import os
import twitter
import re
from django.conf import settings
from sqlalchemy import create_engine
@@ -63,6 +64,22 @@ class PowerZonesField(models.TextField):
if not value: return
if isinstance(value, list):
return value
# remove double quotes and brackets
print value
value = re.sub(r'u\"','',value)
value = re.sub(r'u\'','',value)
value = re.sub(r'\\','',value)
value = re.sub(r'\"','',value)
value = re.sub(r'\'','',value)
value = re.sub(r'\[','',value)
value = re.sub(r'\]','',value)
value = re.sub(r'\[\[','[',value)
value = re.sub(r'\]\]',']',value)
value = re.sub(r'\ \ ',' ',value)
value = re.sub(r', ',',',value)
print "aap"
print value
return value.split(self.token)
def from_db_value(self,value, expression, connection, context):
@@ -100,7 +117,7 @@ class TeamInvite(models.Model):
user = models.ForeignKey(User,null=True)
issuedate = models.DateField(default=timezone.now)
code = models.CharField(max_length=150,unique=True)
email = models.CharField(max_length=150,null=True,blank=True)
# Extension of User with rowing specific data
class Rower(models.Model):
@@ -310,7 +327,7 @@ class Workout(models.Model):
)
user = models.ForeignKey(Rower)
team = models.ForeignKey(Team,blank=True,null=True)
team = models.ManyToManyField(Team,blank=True,null=True)
name = models.CharField(max_length=150)
date = models.DateField()
workouttype = models.CharField(choices=workouttypes,max_length=50)

View File

@@ -54,6 +54,40 @@ def handle_sendemail_unrecognized(unrecognizedfile,useremail):
os.remove(unrecognizedfile)
return 1
# Send email with team invitation
@app.task
def handle_sendemail_invite(email,name,code,teamname,manager):
fullemail = name+' <'+email+'>'
subject = 'Invitation to join team '+teamname
message = 'Dear '+name+',\n\n'
message += manager+' is inviting you to join his team '+teamname
message += ' on rowsandall.com\n\n'
message += 'If you already have an account on rowsandall.com, you can login to the site and you will find the invitation here on the Teams page:\n'
message += ' https://rowsandall.com/rowers/me/teams \n\n'
message += 'You can also click the direct link: \n'
message += 'https://rowsandall.com/rowers/me/invitation/'+code+' \n\n'
message += 'If you are not yet registered to rowsandall.com, '
message += 'you can register for free at https://rowsandall.com/rowers/register\n'
message += 'After you set up your account, you can use the direct link: '
message += 'https://rowsandall.com/rowers/me/invitation/'+code+' \n\n'
message += 'You can also manually accept your team membership with the code.\n'
message += 'You will need to do this if you registered under a differnt email address than this one.\n'
message += 'Code: '+code+'\n'
message += 'Link to manually accept your team membership: '
message += 'https://rowsandall.com/rowers/me/invitation\n\n'
message += "Best Regards, the Rowsandall Team"
email = EmailMessage(subject, message,
'Rowsandall <info@rowsandall.com>',
[fullemail])
res = email.send()
return 1
# Send email with TCX attachment
@app.task
def handle_sendemailtcx(first_name,last_name,email,tcxfile):

View File

@@ -8,12 +8,16 @@ import time
from django.db import IntegrityError
import uuid
from rowers.tasks import handle_sendemail_invite
from rowers.models import (
Rower, Workout, Team, TeamInvite,User
)
# Low level functions - to be called by higher level methods
inviteduration = 14 # days
def create_team(name,manager,notes=''):
# needs some error testing
try:
@@ -32,23 +36,41 @@ def remove_team(id):
def add_member(id,rower):
t= Team.objects.get(id=id)
rower.team.add(t)
# code to add all workouts
ws = Workout.objects.filter(user=rower)
for w in ws:
w.team.add(t)
return (1,'Member added')
def remove_member(id,rower):
t = Team.objects.get(id=id)
rower.team.remove(t)
# remove the team from rower's workouts:
ws = Workout.objects.filter(user=rower)
for w in ws:
w.team.remove(t)
return (1,'Member removed')
def mgr_remove_member(id,manager,rower):
t = Team.objects.get(id=id)
if t.manager == manager:
rower.team.remove(t)
return (1,'Member added')
remove_member(id,rower)
return (1,'Member removed')
else:
return (0,'You are not the team manager')
return 0
def count_invites(manager):
ts = Team.objects.filter(manager=manager)
count = 0
for t in ts:
count += TeamInvite.objects.filter(team=t).count()
return count
def count_members(id):
t = Team.objects.get(id=id)
return Rower.objects.filter(team=t).count()
@@ -65,9 +87,14 @@ def get_team_members(id):
t = Team.objects.get(id=id)
return Rower.objects.filter(team=t)
def get_team_workouts(id):
t = Team.objects.get(id=id)
return Workout.objects.filter(team=t).order_by("-date", "-starttime")
# Medium level functionality
def create_invite(team,manager,user=None):
r = Rower.objects.get(user=manager)
if team.manager != manager:
return (0,'Not the team manager')
if user:
@@ -77,7 +104,7 @@ def create_invite(team,manager,user=None):
return (0,'Rower does not exist')
if r2 in Rower.objects.filter(team=team):
return (0,'Already member of that team')
if count_club_members(team.manager) < r.clubsize:
if count_club_members(team.manager)+count_invites(team.manager) < r.clubsize:
codes = [i.code for i in TeamInvite.objects.all()]
code = uuid.uuid4().hex[:10].upper()
# prevent duplicates
@@ -86,10 +113,63 @@ def create_invite(team,manager,user=None):
invite = TeamInvite(team=team,code=code,user=user)
invite.save()
return code
return (invite.id,'Invitation created')
else:
return (0,'You are at your club size limit')
return (0,'Nothing done')
def revoke_invite(id):
invitation = TeamInvite.objects.get(id=id)
invitation.delete()
return (1,'Invitation revoked')
def send_invite_email(id):
invitation = TeamInvite.objects.get(id=id)
if invitation.user:
email = invitation.user.email
name = invitation.user.first_name + " " + invitation.user.last_name
else:
email = invitation.email
code = invitation.code
teamname = invitation.team.name
manager = invitation.team.manager.first_name+' '+invitation.team.manager.last_name
if settings.DEBUG:
res = handle_sendemail_invite(email,name,code,teamname,manager)
else:
res = queue.enqueue(handle_sendemail_invite(email,name,code,
teamname,
manager))
return (1,'Invitation email sent')
def process_invite_code(user,code):
try:
invitation = TeamInvite.objects.get(code=code)
except TeamInvite.DoesNotExist:
return (0,'The invitation has expired or the code is invalid')
r = Rower.objects.get(user=user)
nu = datetime.date(timezone.now())
if nu > invitation.issuedate+timedelta(days=inviteduration):
revoke_invite(invitation.id)
return (0,'The invitation has expired')
t = invitation.team
result = add_member(t.id,r)
invitation.delete()
return result
def remove_expired_invites():
issuedate = timezone.now()-timedelta(days=inviteduration)
issuedate = datetime.date(issuedate)
invitations = TeamInvite.objects.filter(issuedate__lt=issuedate)
for i in invitations:
revoke_invite(i.id)
return (1,'Expired invitations deleted')

View File

@@ -98,7 +98,7 @@
<div class="grid_8 omega">
{% if cordict %}
<h2> Correlation Matrix</h2>
<p>This table indicates a positive (+) or negative (-) correlation between two parameters. The strong correlations are indicated with ++ and --.
<p>This matrix indicates a positive (+) or negative (-) correlation between two parameters. The Spearman correlation coefficient has values between +1 and -1. Positive correlation between two metrics means that if one metric increases, the other value is also likely to increase. Negative is the opposite. The further from zero, the higher the likelyhood.
</p>
<table width="90%" class="cortable">
<thead>
@@ -116,13 +116,13 @@
{% for key2,value in thedict.items %}
<td>
{% if value > 0.5 %}
<div class="poscor">++</div>
<div class="poscor">{{ value|floatformat:-1 }}</div>
{% elif value > 0.1 %}
<div class="weakposcor">+</div>
<div class="weakposcor">{{ value|floatformat:-1 }}</div>
{% elif value < -0.5 %}
<div class="negcor">--</div>
<div class="negcor">{{ value|floatformat:-1 }}</div>
{% elif value < -0.1 %}
<div class="weaknegcor">-</div>
<div class="weaknegcor">{{ value|floatformat:-1 }}</div>
{% else %}
&nbsp;
{% endif %}

View File

@@ -3,107 +3,124 @@
{% block title %}Change Rower {% endblock %}
{% block content %}
<div class="grid_6 alpha">
<p>
<h2>Heart Rate Zones</h2>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<div class="grid_2 prefix_2 suffix_2">
<input class="button green" type="submit" value="Save">
</form>
</p>
</div>
<p>
<h2>Account Information</h2>
{% if userform.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
{% if accountform.errors %}
<p style="color: red;">
</p>
{% endif %}
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ userform.as_table }}
{{ accountform.as_table }}
<tr>
<td>Plan</td><td>{{ rower.rowerplan }}</td>
</tr>
</table>
{% csrf_token %}
<div class="grid_2 prefix_2 suffix_2">
<input class="button green" type="submit" value="Save">
</form>
</div>
</p>
</div>
<div class="grid_6 omega">
<p>
<h2>Power Zones</h2>
<div class="grid_12 alpha">
<div class="grid_6 alpha">
<p>
<h2>Heart Rate Zones</h2>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form enctype="multipart/form-data" action="" method="post">
{% if powerzonesform.errors %}
<p style="color: red;">
Please correct the error{{ powerzonesform.errors|pluralize }} below.
{{ powerzonesform.non_field_errors }}
</p>
{% endif %}
<table>
<thead>
<tr>
<th>ID</th><th>Zone Name</th><th>Lower Boundary (Watt)</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td><td>{{ powerzonesform.ut3name }}</td>
<td></td>
</tr>
<tr>
<td>2</td><td>{{ powerzonesform.ut2name }}</td>
<td>{{ powerzonesform.pw_ut2 }}</td>
</tr>
<tr>
<td>3</td><td>{{ powerzonesform.ut1name }}</td>
<td>{{ powerzonesform.pw_ut1 }}</td>
</tr>
<tr>
<td>4</td><td>{{ powerzonesform.atname }}</td>
<td>{{ powerzonesform.pw_at }}</td>
</tr>
<tr>
<td>5</td><td>{{ powerzonesform.trname }}</td>
<td>{{ powerzonesform.pw_tr }}</td>
</tr>
<tr>
<td>6</td><td>{{ powerzonesform.anname }}</td>
<td>{{ powerzonesform.pw_an }}</td>
</tr>
</tbody>
{{ form.as_table }}
</table>
{% csrf_token %}
<div class="grid_2 prefix_2 suffix_2">
<input class="button green" type="submit" value="Save">
</div>
</form>
</p>
<p>
<h2>Functional Threshold Power</h2>
<p>Use this form to quickly change your zones based on the power of a
recent
full out 60 minutes effort. It will update all zones defined above.</p>
</p>
</div>
</div>
<div class="grid_6 omega">
<p>
<h2>Power Zones</h2>
<form enctype="multipart/form-data" action="" method="post">
{% if powerzonesform.errors %}
<p style="color: red;">
Please correct the error{{ powerzonesform.errors|pluralize }} below.
{{ powerzonesform.non_field_errors }}
</p>
{% endif %}
<table>
<thead>
<tr>
<th>ID</th><th>Zone Name</th><th>Lower Boundary (Watt)</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td><td>{{ powerzonesform.ut3name }}</td>
<td></td>
</tr>
<tr>
<td>2</td><td>{{ powerzonesform.ut2name }}</td>
<td>{{ powerzonesform.pw_ut2 }}</td>
</tr>
<tr>
<td>3</td><td>{{ powerzonesform.ut1name }}</td>
<td>{{ powerzonesform.pw_ut1 }}</td>
</tr>
<tr>
<td>4</td><td>{{ powerzonesform.atname }}</td>
<td>{{ powerzonesform.pw_at }}</td>
</tr>
<tr>
<td>5</td><td>{{ powerzonesform.trname }}</td>
<td>{{ powerzonesform.pw_tr }}</td>
</tr>
<tr>
<td>6</td><td>{{ powerzonesform.anname }}</td>
<td>{{ powerzonesform.pw_an }}</td>
</tr>
</tbody>
</table>
{% csrf_token %}
<div class="grid_2 prefix_2 suffix_2">
<input class="button green" type="submit" value="Save">
</div>
</form>
</p>
</div>
</div>
<div class="grid_12 alpha">
<div class="grid_6 alpha">
<p>
<h2>Account Information</h2>
{% if userform.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
{% if accountform.errors %}
<p style="color: red;">
</p>
{% endif %}
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ userform.as_table }}
{{ accountform.as_table }}
<tr>
<th>Plan</th><td>{{ rower.rowerplan }}</td>
</tr>
<tr>
<th>Plan Expiry</th><td>{{ rower.planexpires }}</td>
</tr>
</table>
{% csrf_token %}
<div class="grid_2 alpha">
{% if rower.rowerplan == 'basic' %}
<a class="button blue" href="/rowers/promembership">Upgrade</a>
{% else %}
&nbsp;
{% endif %}
</div>
<div class="grid_2 suffix_2 omega">
<input class="button green" type="submit" value="Save">
</form>
</div>
</p>
</div>
<div class="grid_6 omega">
<p>
<h2>Functional Threshold Power</h2>
<p>Use this form to quickly change your zones based on the power of a
recent
full out 60 minutes effort. It will update all zones defined above.</p>
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ powerform.as_table }}
@@ -113,43 +130,61 @@
<input class="button green" type="submit" value="Save">
</form>
</div>
</p>
{% if grants %}
<p>
<h2>Applications</h2>
<table width="100%">
<thead>
<tr>
<th>Application</th>
<th>Scope</th>
<th>Revoke</th>
</tr>
</thead>
<tbody>
{% for grant in grants %}
<tr>
<td>{{ grant.application }}</td>
<td>{{ grant.scope }}</td>
<td>
<a class="button red small" href="/rowers/me/revokeapp/{{ grant.application.id }}">Revoke</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</p>
{% endif %}
</div>
</div>
<div class="grid_12 alpha">
<div class="grid_6 alpha">
<p>
<h2>Teams</h2>
<div class="grid_2 suffix_4 alpha">
<a class="button gray small" href="/rowers/me/teams">Manage Teams</a>
</div>
</p>
</div>
<div class="grid_6 omega">
<p>
<h2>Favorite Charts</h2>
<div class="grid_2 suffix_4 alpha">
<a class="button gray small" href="/rowers/me/favoritecharts">Manage Favorite Charts</a>
</div>
</p>
</div>
</div>
<div class="grid_6 prefix_6 alpha">
<p>
<h2>Favorite Charts</h2>
<div class="grid_2 suffix_4 alpha">
<a class="button gray small" href="/rowers/me/favoritecharts">Manage Favorite Charts</a>
</div>
</p>
<div class="grid_12 alpha">
<div class="grid_6 suffix_6 alpha">
{% if grants %}
<p>
<h2>Applications</h2>
<table width="100%">
<thead>
<tr>
<th>Application</th>
<th>Scope</th>
<th>Revoke</th>
</tr>
</thead>
<tbody>
{% for grant in grants %}
<tr>
<td>{{ grant.application }}</td>
<td>{{ grant.scope }}</td>
<td>
<a class="button red small" href="/rowers/me/revokeapp/{{ grant.application.id }}">Revoke</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</p>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
</div>
{% endblock %}

View File

@@ -75,8 +75,8 @@
</div>
<div class="grid_8 omega">
{% if cordict %}
<h2> Correlation table</h2>
<p>This table indicates a positive (+) or negative (-) correlation between two parameters. The strong correlations are indicated with ++ and --.
<h2> Correlation matrix</h2>
<p>This matrix indicates a positive (+) or negative (-) correlation between two parameters. The Spearman correlation coefficient has values between +1 and -1. Positive correlation between two metrics means that if one metric increases, the other value is also likely to increase. Negative is the opposite. The further from zero, the higher the likelyhood.
</p>
<table width="90%" class="cortable">
<thead>
@@ -94,13 +94,13 @@
{% for key2,value in thedict.items %}
<td>
{% if value > 0.5 %}
<div class="poscor">++</div>
<div class="poscor">{{ value|floatformat:-1 }}</div>
{% elif value > 0.1 %}
<div class="weakposcor">+</div>
<div class="weakposcor">{{ value|floatformat:-1 }}</div>
{% elif value < -0.5 %}
<div class="negcor">--</div>
<div class="negcor">{{ value|floatformat:-1 }}</div>
{% elif value < -0.1 %}
<div class="weaknegcor">-</div>
<div class="weaknegcor">{{ value|floatformat:-1 }}</div>
{% else %}
&nbsp;
{% endif %}