From bdeed4c2776a2f0cbadb9f82f19c37df99aa4b19 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Wed, 31 Jul 2019 13:17:52 +0200
Subject: [PATCH 1/2] email from group page
---
rowers/forms.py | 9 ++++++++-
rowers/models.py | 2 +-
rowers/tasks.py | 19 ++++++++++++++++++
rowers/teams.py | 20 ++++++++++++++++---
rowers/templates/team.html | 13 ++++++++++++
rowers/templates/teammessage.html | 14 +++++++++++++
rowers/views/statements.py | 2 +-
rowers/views/teamviews.py | 33 +++++++++++++++++++++----------
8 files changed, 96 insertions(+), 16 deletions(-)
create mode 100644 rowers/templates/teammessage.html
diff --git a/rowers/forms.py b/rowers/forms.py
index 3a529876..0be90550 100644
--- a/rowers/forms.py
+++ b/rowers/forms.py
@@ -1206,7 +1206,14 @@ class WorkoutRaceSelectForm(forms.Form):
)
# self.fields['evaluate_after'] =
-
+
+# form to send messages to team members
+class TeamMessageForm(forms.Form):
+ message = forms.CharField(required=True,
+ initial='',
+ widget=forms.Textarea()
+ )
+
# Form to select team by rower
class RowerTeamForm(forms.Form):
team = forms.ModelChoiceField(
diff --git a/rowers/models.py b/rowers/models.py
index 6aec9f3a..7b42bf24 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -861,7 +861,7 @@ class Rower(models.Model):
privacy = models.CharField(default='visible',max_length=30,
choices=privacychoices)
- team = models.ManyToManyField(Team,blank=True)
+ team = models.ManyToManyField(Team,blank=True,related_name='rower')
# Export and Time Zone Settings
defaulttimezone = models.CharField(default='UTC',max_length=100,
diff --git a/rowers/tasks.py b/rowers/tasks.py
index a3ffea10..05a0534d 100644
--- a/rowers/tasks.py
+++ b/rowers/tasks.py
@@ -1982,6 +1982,25 @@ def handle_sendemailnewcomment(first_name,
return 1
+@app.task
+def handle_sendemail_message(email,fromemail,rowername,message,teamname,managername,
+ debug=False,**kwargs):
+
+ fullemail = email
+ subject = 'New message from team ' + teamname
+ from_email = fromemail
+
+ d = {
+ 'rowername':rowername,
+ 'teamname':teamname,
+ 'managername':managername,
+ 'message':message,
+ }
+
+ res = send_template_email(from_email,[fullemail],subject,
+ 'teammessage.html',d,**kwargs)
+
+ return 1
@app.task
def handle_sendemail_request(email, name, code, teamname, requestor, id,
diff --git a/rowers/teams.py b/rowers/teams.py
index 7a99f6d3..5e550cc0 100644
--- a/rowers/teams.py
+++ b/rowers/teams.py
@@ -37,6 +37,7 @@ from rowers.tasks import (
handle_sendemail_coachoffer_accepted,
handle_sendemail_coachrequest_rejected,
handle_sendemail_coachrequest_accepted,
+ handle_sendemail_message,
)
from rowers.models import ValidationError
@@ -173,8 +174,11 @@ def remove_coach(coach,rower):
def rower_get_coaches(rower):
coaches = []
for group in rower.coachinggroups.all():
- coach = Rower.objects.get(mycoachgroup=group)
- coaches.append(coach)
+ try:
+ coach = Rower.objects.get(mycoachgroup=group)
+ coaches.append(coach)
+ except Rower.DoesNotExist:
+ pass
return coaches
@@ -567,7 +571,17 @@ def send_invite_accept_email(invitation):
return (1,'Invitation email sent')
+def send_team_message(team,message):
+ rowers = team.rower.all()
+ managername = team.manager.first_name + " " + team.manager.last_name
+ for rower in rowers:
+ rowername = rower.user.first_name + " " + rower.user.last_name
+ res = myqueue(queuehigh,
+ handle_sendemail_message,
+ rower.user.email,team.manager.email,rowername,message,team.name,managername)
+
+ return (1,'message sent')
def send_request_email(rekwest):
email = rekwest.team.manager.email
@@ -606,7 +620,7 @@ def process_request_code(manager,code):
rekwest.delete()
- return result
+ return (result,'The member was added')
def process_invite_code(user,code):
code = code.upper()
diff --git a/rowers/templates/team.html b/rowers/templates/team.html
index 242abdd5..59c0fc34 100644
--- a/rowers/templates/team.html
+++ b/rowers/templates/team.html
@@ -72,6 +72,19 @@
{% endif %}
+
+ {% if team.manager == user %}
+ Message
+ Use this form to send a message to all team members by email.
+
+ {% endif %}
+
diff --git a/rowers/templates/teammessage.html b/rowers/templates/teammessage.html
new file mode 100644
index 00000000..a660c5af
--- /dev/null
+++ b/rowers/templates/teammessage.html
@@ -0,0 +1,14 @@
+{% extends "emailbase.html" %}
+
+{% block body %}
+Dear {{ first_name }},
+
+
+ Here is a message from {{ managername }}, the team manager of rowsandall.com team {{ teamname }}.
+
+
+
+ {{ message }}
+
+
+{% endblock %}
diff --git a/rowers/views/statements.py b/rowers/views/statements.py
index e2b470c3..dd155ce5 100644
--- a/rowers/views/statements.py
+++ b/rowers/views/statements.py
@@ -48,7 +48,7 @@ from django.http import (
)
from django.contrib.auth import authenticate, login, logout
from rowers.forms import (
- ForceCurveOptionsForm,HistoForm,
+ ForceCurveOptionsForm,HistoForm,TeamMessageForm,
LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,CourseForm,
TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm,
WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement,
diff --git a/rowers/views/teamviews.py b/rowers/views/teamviews.py
index b1c730a4..8610beaa 100644
--- a/rowers/views/teamviews.py
+++ b/rowers/views/teamviews.py
@@ -27,7 +27,7 @@ def team_view(request,id=0,userid=0):
q = q | q2
- if request.method == 'POST' and request.user == t.manager:
+ if request.method == 'POST' and request.user == t.manager and 'email' in request.POST:
inviteform = TeamInviteForm(request.POST)
inviteform.fields['user'].queryset = q
@@ -45,12 +45,24 @@ def team_view(request,id=0,userid=0):
else:
message = text
messages.error(request,message)
+ groupmessageform = TeamMessageForm()
+ elif request.method == 'POST' and request.user == t.manager and 'message' in request.POST:
+ groupmessageform = TeamMessageForm(request.POST)
+ inviteform = TeamInviteForm()
+ if groupmessageform.is_valid():
+ message = groupmessageform.cleaned_data['message']
+ teams.send_team_message(t,message)
+ messages.info(request,'Message was sent to all team members')
+ groupmessageform = TeamMessageForm()
elif request.user == t.manager:
inviteform = TeamInviteForm()
inviteform.fields['user'].queryset = q
+ groupmessageform = TeamMessageForm()
else:
inviteform = ''
+ groupmessageform = ''
+
members = Rower.objects.filter(team=t).order_by('user__last_name','user__first_name')
thisteammyrequests = TeamRequest.objects.filter(team=t,user=request.user)
@@ -63,7 +75,7 @@ def team_view(request,id=0,userid=0):
breadcrumbs = [
{
'url':reverse(rower_teams_view),
- 'name': 'Teams'
+ 'name': 'Groups'
},
{
'url':reverse(team_view,kwargs={'id':id}),
@@ -78,6 +90,7 @@ def team_view(request,id=0,userid=0):
'teams':get_my_teams(request.user),
'myteams':myteams,
'memberteams':memberteams,
+ 'groupmessageform': groupmessageform,
'members':members,
'breadcrumbs':breadcrumbs,
'active':'nav-teams',
@@ -98,7 +111,7 @@ def team_leaveconfirm_view(request,id=0):
breadcrumbs = [
{
'url':reverse(rower_teams_view),
- 'name': 'Teams'
+ 'name': 'Groups'
},
{
'url':reverse(team_view,kwargs={'id':id}),
@@ -242,7 +255,7 @@ def rower_teams_view(request,message='',successmessage=''):
breadcrumbs = [
{
'url':reverse(rower_teams_view),
- 'name': 'Teams'
+ 'name': 'Groups'
}
]
@@ -328,7 +341,7 @@ def athlete_drop_coach_confirm_view(request,id):
breadcrumbs = [
{
'url':reverse('rower_teams_view'),
- 'name': 'Teams'
+ 'name': 'Groups'
},
{
'url':reverse('athlete_drop_coach_confirm_view',kwargs={'id':id}),
@@ -355,7 +368,7 @@ def coach_drop_athlete_confirm_view(request,id):
breadcrumbs = [
{
'url':reverse('rower_teams_view'),
- 'name': 'Teams'
+ 'name': 'Groups'
},
{
'url':reverse('coach_drop_athlete_confirm_view',kwargs={'id':id}),
@@ -609,7 +622,7 @@ def team_edit_view(request,id=0):
breadcrumbs = [
{
'url':reverse(rower_teams_view),
- 'name': 'Teams'
+ 'name': 'Groups'
},
{
'url':reverse(team_view,kwargs={'id':id}),
@@ -675,7 +688,7 @@ def team_create_view(request):
breadcrumbs = [
{
'url':reverse(rower_teams_view),
- 'name': 'Teams'
+ 'name': 'Groups'
},
{
'url':reverse(team_create_view),
@@ -708,7 +721,7 @@ def team_deleteconfirm_view(request,id):
breadcrumbs = [
{
'url':reverse(rower_teams_view),
- 'name': 'Teams'
+ 'name': 'Groups'
},
{
'url':reverse(team_view,kwargs={'id':id}),
@@ -764,7 +777,7 @@ def team_members_stats_view(request,id):
breadcrumbs = [
{
'url':reverse(rower_teams_view),
- 'name': 'Teams'
+ 'name': 'Groups'
},
{
'url':reverse(team_view,kwargs={'id':id}),
From fca58e740f7ec9da79815511213b7ed366038afc Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Wed, 31 Jul 2019 14:12:06 +0200
Subject: [PATCH 2/2] adding calendar to all team members sending funct
---
rowers/tasks.py | 38 +++++++++++++
rowers/teams.py | 7 +++
rowers/templates/icsemail.html | 6 ++-
rowers/templates/plannedsessionscoach.html | 15 +++++-
rowers/templatetags/rowerfilters.py | 11 ++++
rowers/urls.py | 3 ++
rowers/views/exportviews.py | 63 ++++++++++++++++++++++
rowers/views/statements.py | 1 +
8 files changed, 141 insertions(+), 3 deletions(-)
diff --git a/rowers/tasks.py b/rowers/tasks.py
index 05a0534d..065ecca4 100644
--- a/rowers/tasks.py
+++ b/rowers/tasks.py
@@ -1321,6 +1321,44 @@ def handle_sendemailcsv(first_name, last_name, email, csvfile,**kwargs):
return 1
+@app.task
+def handle_sendemail_ical(first_name, last_name, email, url, icsfile, **kwargs):
+ # send email with attachment
+ fullemail = first_name + " " + last_name + " " + "<" + email + ">"
+ subject = "Calendar File for your sessions from Rowsandall.com"
+
+ if 'debug' in kwargs:
+ debug = kwargs['debug']
+ else:
+ debug = False
+
+ siteurl = SITE_URL
+ if debug:
+ progressurl = SITE_URL_DEV
+ siteurl = SITE_URL_DEV
+
+
+ d = {'first_name':first_name,
+ 'siteurl':siteurl,
+ 'url':url,
+ }
+
+ from_email = 'Rowsandall '
+
+
+ res = send_template_email(from_email,[fullemail],
+ subject,'icsemail.html',d,
+ attach_file=icsfile,**kwargs)
+
+
+ try:
+ os.remove(csvfile)
+ except:
+ pass
+
+ return 1
+
+
@app.task
def handle_sendemailfile(first_name, last_name, email, csvfile,**kwargs):
diff --git a/rowers/teams.py b/rowers/teams.py
index 5e550cc0..a11cbdae 100644
--- a/rowers/teams.py
+++ b/rowers/teams.py
@@ -171,6 +171,13 @@ def remove_coach(coach,rower):
return (1,'Coach removed')
+def rower_get_managers(rower):
+ managers = []
+ for team in rower.team.all():
+ managers.append(team.manager.rower)
+
+ return managers
+
def rower_get_coaches(rower):
coaches = []
for group in rower.coachinggroups.all():
diff --git a/rowers/templates/icsemail.html b/rowers/templates/icsemail.html
index ffab16ea..4914a4a0 100644
--- a/rowers/templates/icsemail.html
+++ b/rowers/templates/icsemail.html
@@ -4,10 +4,14 @@
Dear {{ first_name }},
- Please find attached the requested ICS Calendar file. You can import
+ Please find attached the ICS Calendar file for your training sessions. You can import
this file to your calendar app.
+
+ You can see the training plan here: {{ siteurl }}{{ url }}
+
+
Best Regards, the Rowsandall Team
diff --git a/rowers/templates/plannedsessionscoach.html b/rowers/templates/plannedsessionscoach.html
index dd0a76fa..23540b2d 100644
--- a/rowers/templates/plannedsessionscoach.html
+++ b/rowers/templates/plannedsessionscoach.html
@@ -6,9 +6,9 @@
{% block main %}
{% if theteam %}
-Coach Overview. Team {{ theteam.name }}
+Group Overview. Team {{ theteam.name }}
{% else %}
-Coach Overview
+Group Overview
{% endif %}
@@ -83,6 +83,17 @@
{% endfor %}
+
+
+ Get Calendar File
+
+ {% if rower|is_coach:rowers %}
+
+
+ Send Calendar File to all rowers
+
+
+ {% endif %}
{% if unmatchedworkouts %}
diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py
index 3ee2a7e2..820c8a54 100644
--- a/rowers/templatetags/rowerfilters.py
+++ b/rowers/templatetags/rowerfilters.py
@@ -66,6 +66,17 @@ def strfdelta(tdelta):
return res
+from rowers.teams import rower_get_managers
+
+@register.filter
+def is_coach(rower,rowers):
+ for r in rowers:
+ if rower not in rower_get_managers(r):
+ print(r,rower)
+ return False
+
+ return True
+
def strfdeltah(tdelta):
hours, rest = divmod(tdelta.seconds,3600)
minutes,seconds = divmod(rest,60)
diff --git a/rowers/urls.py b/rowers/urls.py
index a2271402..02d7b112 100644
--- a/rowers/urls.py
+++ b/rowers/urls.py
@@ -673,6 +673,9 @@ urlpatterns = [
name='plannedsessions_coach_view'),
re_path(r'^sessions/coach/user/(?P\d+)/$',views.plannedsessions_coach_view,
name='plannedsessions_coach_view'),
+ re_path(r'^sessions/coach/sendcalendar/user/(?P\d+)/$',
+ views.plannedsessions_coach_icsemail_view,
+ name='plannedsessions_coach_icsemail_view'),
re_path(r'^sessions/print/?/$',views.plannedsessions_print_view,
name='plannedsessions_print_view'),
re_path(r'^sessions/(?P\d+)/comments/user/(?P\d+)/$',views.plannedsession_comment_view,
diff --git a/rowers/views/exportviews.py b/rowers/views/exportviews.py
index 66496a55..eb9588c8 100644
--- a/rowers/views/exportviews.py
+++ b/rowers/views/exportviews.py
@@ -71,6 +71,69 @@ def plannedsessions_icsemail_view(request,userid=0):
return response
+@login_required()
+def plannedsessions_coach_icsemail_view(request,userid=0):
+ therower = getrequestplanrower(request,userid=userid)
+ startdate,enddate = get_dates_timeperiod(request)
+
+ if 'coach' in request.user.rower.rowerplan:
+ sps = get_sessions_manager(request.user,teamid=0,
+ enddate=enddate,
+ startdate=startdate)
+ else:
+ rteams = therower.team.filter(viewing='allmembers')
+ sps = get_sessions(therower,startdate=startdate,enddate=enddate)
+
+ if therower.rowerplan != 'freecoach':
+ rowers = [therower]
+ else:
+ rowers = []
+
+ rowers = list(set(rowers))
+
+ cal = Calendar()
+ cal.add('prodid','rowsandall')
+ cal.add('version','1.0')
+
+ for ps in sps:
+ event = Event()
+ comment = '{d} {u} {c}'.format(
+ d=ps.sessionvalue,
+ u = ps.sessionunit,
+ c = ps.criterium)
+ event.add('summary',ps.name)
+ event.add('dtstart',ps.preferreddate)
+ event.add('dtend',ps.preferreddate)
+ event['uid'] = 'plannedsession_'+str(ps.id)
+ event.add('description',ps.comment)
+ event.add('comment',comment)
+ cal.add_component(event)
+
+
+ icalstring = cal.to_ical()
+ fname = "media/training_plan_{d1}_{d2}".format(
+ d1 = startdate.strftime("%Y%m%d"),
+ d2 = enddate.strftime("%Y%m%d"),
+ )
+
+ url = reverse('plannedsessions_coach_view')+'?when={d1}/{d2}'.format(
+ d1 = startdate.strftime("%Y-%m-%d"),
+ d2 = enddate.strftime("%Y-%m-%d"),
+ )
+
+ for rower in rowers:
+ fname2 = fname+"_{u}.ics".format(u=rower.id)
+ with open(fname2,'wb') as fop:
+ fop.write(icalstring)
+
+ job = myqueue(queue,handle_sendemail_ical,
+ rower.user.first_name,
+ rower.user.last_name,
+ rower.user.email,
+ url,
+ fname2,debug=False)
+
+ return HttpResponseRedirect(url)
@login_required()
def course_kmldownload_view(request,id=0):
diff --git a/rowers/views/statements.py b/rowers/views/statements.py
index dd155ce5..5dd22c60 100644
--- a/rowers/views/statements.py
+++ b/rowers/views/statements.py
@@ -183,6 +183,7 @@ from rowers.tasks import (
handle_sendemail_userdeleted,
handle_sendemail_raceregistration,
handle_sendemail_racesubmission,
+ handle_sendemail_ical,
)
from scipy.signal import savgol_filter