From 977824d462ea69bef6be4665f9686f59c23cc4bf Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Fri, 16 Mar 2018 11:43:42 +0100
Subject: [PATCH 1/8] added complete date to partially complete sessions
---
rowers/plannedsessions.py | 1 +
rowers/templates/plannedsessions.html | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py
index 45a90c63..b11fab3b 100644
--- a/rowers/plannedsessions.py
+++ b/rowers/plannedsessions.py
@@ -213,6 +213,7 @@ def is_session_complete_ws(ws,ps):
if ratio>cratiomin and ratio {{ ps.sessionvalue }}
| {{ actualvalue|lookup:ps.id }} |
{{ ps.sessionunit }} |
+ {% if completeness|lookup:ps.id == 'partial' %}
+ {{ completiondate|lookup:ps.id|date:"Y-m-d" }} |
+ {% else %}
{{ completiondate|lookup:ps.id|date:"Y-m-d" }} |
+ {% endif %}
{% endfor %}
From 4cdb3f4e6893aa66b84f5cba899340c77378b97c Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Fri, 16 Mar 2018 12:23:41 +0100
Subject: [PATCH 2/8] improved timezone handling of workout edit save form
---
rowers/views.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/rowers/views.py b/rowers/views.py
index d5dc92dc..f2ba6f6b 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -8722,7 +8722,14 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
startdatetime = (str(date) + ' ' + str(starttime))
startdatetime = datetime.datetime.strptime(startdatetime,
"%Y-%m-%d %H:%M:%S")
- startdatetime = timezone.make_aware(startdatetime)
+
+ startdatetime = startdatetime.replace(tzinfo=pytz.timezone(thetimezone))
+ try:
+ # aware object can be in any timezone
+ out = startdatetime.astimezone(pytz.utc)
+ except (ValueError, TypeError):
+ startdatetime = timezone.make_aware(startdatetime)
+
startdatetime = startdatetime.astimezone(pytz.timezone(thetimezone))
From ce974ee884f4a77227ddda254ae400db45745263 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Fri, 16 Mar 2018 16:08:06 +0100
Subject: [PATCH 3/8] AWS working on localhost in debug mode
---
rowers/email.py | 82 ----------------------------------
rowers/emails.py | 31 +++++++++++++
rowers/tasks.py | 8 +++-
rowsandall_app/settings.py | 4 --
rowsandall_app/settings_dev.py | 18 +++++---
startcelery.bat | 3 +-
6 files changed, 53 insertions(+), 93 deletions(-)
delete mode 100644 rowers/email.py
create mode 100644 rowers/emails.py
diff --git a/rowers/email.py b/rowers/email.py
deleted file mode 100644
index b7f6cbf4..00000000
--- a/rowers/email.py
+++ /dev/null
@@ -1,82 +0,0 @@
-import time
-from django.views.generic.base import TemplateView
-from django.shortcuts import render
-from django.http import HttpResponse, HttpResponseRedirect
-from django.contrib.auth import authenticate, login, logout
-from rowers.forms import LoginForm,DocumentsForm,UploadOptionsForm
-from django.core.urlresolvers import reverse
-from django.conf import settings
-from django.utils.datastructures import MultiValueDictKeyError
-from django.utils import timezone,translation
-from django.core.mail import send_mail, BadHeaderError
-from rowers.forms import EmailForm, RegistrationForm, RegistrationFormTermsOfService,RegistrationFormUniqueEmail,CNsummaryForm,UpdateWindForm,UpdateStreamForm
-from rowers.forms import PredictedPieceForm
-from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage,AdvancedWorkoutForm
-import StringIO
-from django.contrib.auth.decorators import login_required,user_passes_test
-from time import strftime,strptime,mktime,time,daylight
-import os,sys
-import datetime
-import iso8601
-import c2stuff
-from c2stuff import C2NoTokenError
-from iso8601 import ParseError
-import stravastuff
-import sporttracksstuff
-from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET
-from rowsandall_app.settings import SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI, SPORTTRACKS_CLIENT_SECRET
-import requests
-import json
-from rowers.rows import handle_uploaded_file
-from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx
-from scipy.signal import savgol_filter
-
-from rowingdata import rower as rrower
-from rowingdata import main as rmain
-from rowingdata import rowingdata as rdata
-from rowingdata import TCXParser,RowProParser,ErgDataParser,TCXParserNoHR
-from rowingdata import painsledDesktopParser,speedcoachParser,ErgStickParser
-from rowingdata import SpeedCoach2Parser,FITParser,fitsummarydata
-from rowingdata import make_cumvalues
-from rowingdata import summarydata,get_file_type
-import pandas as pd
-import numpy as np
-import matplotlib.pyplot as plt
-from pytz import timezone as tz,utc
-import dateutil
-import mpld3
-from mpld3 import plugins
-import stravalib
-from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
-from weather import get_wind_data
-
-import django_rq
-queue = django_rq.get_queue('default')
-queuelow = django_rq.get_queue('low')
-queuehigh = django_rq.get_queue('low')
-
-import plots
-
-from io import BytesIO
-from scipy.special import lambertw
-
-# used in shell to send a newsletter to all Rowers
-def emailall(emailfile,subject):
- rowers = Rower.objects.all()
- for rower in rowers:
- email = rower.user.email
- firstname = rower.user.first_name
-
- print email
-
- with open(emailfile) as f:
- message = f.read()
-
- message = '\nDear '+firstname+',\n\n'+str(message)
-
- send_mail(
- subject,
- message,
- 'info@rowsandall.com',
- [email],
- )
diff --git a/rowers/emails.py b/rowers/emails.py
new file mode 100644
index 00000000..a5682019
--- /dev/null
+++ b/rowers/emails.py
@@ -0,0 +1,31 @@
+from django.core.mail.message import MIMEText
+#from email.mime.application import MIMEApplication
+from django.core.mail.message import MIMEMultipart
+
+# boto3 email functionality
+import boto3
+AWS_REGION = "us-west-2"
+CHARSET = "UTF-8"
+client = boto3.client('ses',region_name=AWS_REGION)
+
+def sendemail(fromaddress,recipients,subjecttext,bodytext,attachment=None):
+ msg = MIMEMultipart()
+ msg['Subject'] = subjecttext
+ msg['From'] = fromaddress
+ msg['To'] = recipients
+ part = MIMEText(bodytext)
+ msg.attach(part)
+
+ # if attachment:
+ # part = MIMEApplication(open(attachment,'rb').read())
+ # part.add_header('Content-Disposition', 'attachment',
+ # filename=attachment)
+ # msg.attach(part)
+
+ result = client.send_raw_email(
+ Source=msg['From'],
+ Destination=msg['To'],
+ RawMessage=msg
+ )
+
+ return result
diff --git a/rowers/tasks.py b/rowers/tasks.py
index 10d72f3a..ebac2355 100644
--- a/rowers/tasks.py
+++ b/rowers/tasks.py
@@ -52,6 +52,7 @@ import arrow
# testing task
+
@app.task
def add(x, y):
return x + y
@@ -547,11 +548,13 @@ def handle_sendemailsummary(first_name, last_name, email, csvfile, **kwargs):
pass
return 1
-
+
+#from rowers.emails import sendemail
@app.task
def handle_sendemailcsv(first_name, last_name, email, csvfile,**kwargs):
+
# send email with attachment
fullemail = first_name + " " + last_name + " " + "<" + email + ">"
subject = "File from Rowsandall.com"
@@ -559,6 +562,8 @@ def handle_sendemailcsv(first_name, last_name, email, csvfile,**kwargs):
message += "Please find attached the requested file for your workout.\n\n"
message += "Best Regards, the Rowsandall Team"
+
+
email = EmailMessage(subject, message,
'Rowsandall ',
[fullemail])
@@ -573,6 +578,7 @@ def handle_sendemailcsv(first_name, last_name, email, csvfile,**kwargs):
email.attach_file(csvfile2)
os.remove(csvfile2)
+
res = email.send()
return 1
diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py
index 062c0602..62f79fd1 100644
--- a/rowsandall_app/settings.py
+++ b/rowsandall_app/settings.py
@@ -317,14 +317,10 @@ CACHE_MIDDLEWARE_SECONDS = 900
EMAIL_BACKEND = CFG['email_backend']
EMAIL_HOST = CFG['email_host']
-#EMAIL_HOST = 'smtp.rosti.cz'
-#EMAIL_PORT = '25'
EMAIL_PORT = CFG['email_port']
EMAIL_HOST_USER = CFG['email_host_user']
-#EMAIL_HOST_PASSWORD = 'lnD3mbZ1NoI8RK1StOdO'
EMAIL_HOST_PASSWORD = CFG['email_host_password']
EMAIL_USE_TLS = CFG['email_use_tls']
-#EMAIL_USE_TLS = False
DEFAULT_FROM_EMAIL = 'admin@rowsandall.com'
diff --git a/rowsandall_app/settings_dev.py b/rowsandall_app/settings_dev.py
index b37aaed8..402beaf2 100644
--- a/rowsandall_app/settings_dev.py
+++ b/rowsandall_app/settings_dev.py
@@ -83,8 +83,16 @@ SITE_URL = "http://localhost:8000"
#EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
#EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
-#EMAIL_HOST = 'localhost'
-#EMAIL_PORT = '1025'
-#EMAIL_HOST_USER = ''
-#EMAIL_HOST_PASSWORD = ''
-#EMAIL_USE_TLS = True
+EMAIL_BACKEND = 'django_ses.SESBackend'
+
+AWS_SES_REGION_NAME = 'us-west-2'
+AWS_SES_REGION_ENDPOINT = 'email.us-west-2.amazonaws.com'
+
+EMAIL_HOST = CFG['aws_smtp']
+EMAIL_PORT = CFG['aws_port']
+EMAIL_HOST_USER = CFG['aws_smtp_username']
+EMAIL_HOST_PASSWORD = CFG['aws_smtp_password']
+EMAIL_USE_TLS = CFG['email_use_tls']
+DEFAULT_FROM_EMAIL = 'info@rowsandall.com'
+
+
diff --git a/startcelery.bat b/startcelery.bat
index 9ebc51a0..d3de3649 100644
--- a/startcelery.bat
+++ b/startcelery.bat
@@ -1 +1,2 @@
-celery -A rowers.tasks worker --loglevel=info --pool=solo
\ No newline at end of file
+celery -A rowers purge
+celery -A rowers.tasks worker --loglevel=info --pool=solo
From c72cb70e35c0bd0443f7572aa8237b6e855807ef Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Sat, 17 Mar 2018 14:40:57 +0100
Subject: [PATCH 4/8] changed AWS SES region to eu-west
---
rowsandall_app/settings_dev.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/rowsandall_app/settings_dev.py b/rowsandall_app/settings_dev.py
index 402beaf2..ab878ab7 100644
--- a/rowsandall_app/settings_dev.py
+++ b/rowsandall_app/settings_dev.py
@@ -85,8 +85,8 @@ SITE_URL = "http://localhost:8000"
EMAIL_BACKEND = 'django_ses.SESBackend'
-AWS_SES_REGION_NAME = 'us-west-2'
-AWS_SES_REGION_ENDPOINT = 'email.us-west-2.amazonaws.com'
+AWS_SES_REGION_NAME = 'eu-west-1'
+AWS_SES_REGION_ENDPOINT = 'email.eu-west-1.amazonaws.com'
EMAIL_HOST = CFG['aws_smtp']
EMAIL_PORT = CFG['aws_port']
From 9e514d25787edc54a3b35bc5f443e0aa567b0efe Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Sat, 17 Mar 2018 18:10:04 +0100
Subject: [PATCH 5/8] search for inf in update fitness metrics
---
rowers/dataprepnodjango.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/rowers/dataprepnodjango.py b/rowers/dataprepnodjango.py
index 2c5c6d14..e9e3cd10 100644
--- a/rowers/dataprepnodjango.py
+++ b/rowers/dataprepnodjango.py
@@ -677,10 +677,14 @@ def getsmallrowdata_db(columns,ids=[],debug=False):
def fitnessmetric_to_sql(m,table='powertimefitnessmetric',debug=False,
doclean=False):
# test if nan among values
- if np.nan in m.values():
+ if np.nan in m.values() or np.inf in m.values():
for key in m.keys():
if np.isnan([m[key]]):
m[key] = -1
+ if m[key] == np.inf:
+ m[key] = -1
+ if -m[key] == np.inf:
+ m[key] = -1
if debug:
engine = create_engine(database_url_debug, echo=False)
From d64cc9485d728f1860b914d0ac919d9e8e6cbbba Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Sat, 17 Mar 2018 19:21:38 +0100
Subject: [PATCH 6/8] email bounce added and updated privacy policy
---
rowers/models.py | 2 ++
rowers/templates/privacypolicy.html | 23 ++++++++++++++++++++++-
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/rowers/models.py b/rowers/models.py
index f8e75a01..c5afa452 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -571,6 +571,8 @@ class Rower(models.Model):
getemailnotifications = models.BooleanField(default=False,
verbose_name='Receive email notifications')
+ emailbounced = models.BooleanField(default=False,
+ verbose_name='Email Address Bounced')
rowerplan = models.CharField(default='basic',max_length=30,
choices=plans)
diff --git a/rowers/templates/privacypolicy.html b/rowers/templates/privacypolicy.html
index 924c63ca..a3faa516 100644
--- a/rowers/templates/privacypolicy.html
+++ b/rowers/templates/privacypolicy.html
@@ -92,7 +92,28 @@
The data protection officer for rowsandall.com is Sander Roosendaal and he may be contacted
at support@rowsandall.com.
-
+
+
+Notifications and Email Policy
+
+
+ Some actions on the site result in an individual email sent to you.
+
+
+
+ We will rarely use mass email to communicate to all our users. These cases
+ are limited to substantial changes in terms and conditions and other
+ announcements impacting the terms on which you use the site. We will
+ it is important to get these messages to you. If you do not with
+ to receive such emails, you can indicate so in the user settings.
+
+
+
+ Other site related communication (new features, outages, bugs,
+ price changes) are communicated through announcements on the
+ website, throught Twitter, Facebook and our blog
+ posts.
+
Data Deletion
From d3e3aa1343e31cd8daa73337d0dfc08a80f66c83 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Sat, 17 Mar 2018 19:39:03 +0100
Subject: [PATCH 7/8] reset emailbounced when user changes email
---
rowers/views.py | 8 ++++++++
templates/basebase.html | 5 +++++
2 files changed, 13 insertions(+)
diff --git a/rowers/views.py b/rowers/views.py
index f2ba6f6b..69efcd63 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -11231,11 +11231,16 @@ def rower_edit_view(request,rowerid=0,message=""):
getemailnotifications = cd['getemailnotifications']
defaulttimezone=cd['defaulttimezone']
u = r.user
+ if u.email != email and len(email):
+ resetbounce = True
+ else:
+ resetbounce = False
if len(first_name):
u.first_name = first_name
u.last_name = last_name
if len(email): ## and check_email_freeforuse(u,email):
u.email = email
+ resetbounce = True
u.save()
@@ -11246,6 +11251,9 @@ def rower_edit_view(request,rowerid=0,message=""):
r.showfavoritechartnotes = showfavoritechartnotes
r.sex = sex
r.birthdate = birthdate
+ if resetbounce and r.emailbounced:
+ print "aap"
+ r.emailbounced = False
r.save()
form = RowerForm(instance=r)
powerform = RowerPowerForm(instance=r)
diff --git a/templates/basebase.html b/templates/basebase.html
index 6aaaac8a..f88878fe 100644
--- a/templates/basebase.html
+++ b/templates/basebase.html
@@ -247,6 +247,11 @@
{{ user.rower.protrialexpires|date_dif|ddays }} days left in Pro trial
{% endif %}
+ {% if user.rower.emailbounced %}
+
+ Your email bounced. Please update your email address in the user settings
+
+ {% endif %}
{% if messages %}
{% for message in messages %}
{% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}
From 33fb1f50860a2d59e07a2cef00147a5bcaf9658e Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Sat, 17 Mar 2018 19:49:29 +0100
Subject: [PATCH 8/8] changed settings to use AWS SES for outgoing email
---
rowsandall_app/settings.py | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py
index 62f79fd1..3842800d 100644
--- a/rowsandall_app/settings.py
+++ b/rowsandall_app/settings.py
@@ -315,13 +315,25 @@ CACHE_MIDDLEWARE_SECONDS = 900
# email stuff
-EMAIL_BACKEND = CFG['email_backend']
-EMAIL_HOST = CFG['email_host']
-EMAIL_PORT = CFG['email_port']
-EMAIL_HOST_USER = CFG['email_host_user']
-EMAIL_HOST_PASSWORD = CFG['email_host_password']
+#EMAIL_BACKEND = CFG['email_backend']
+#EMAIL_HOST = CFG['email_host']
+#EMAIL_PORT = CFG['email_port']
+#EMAIL_HOST_USER = CFG['email_host_user']
+#EMAIL_HOST_PASSWORD = CFG['email_host_password']
+#EMAIL_USE_TLS = CFG['email_use_tls']
+#DEFAULT_FROM_EMAIL = 'admin@rowsandall.com'
+
+EMAIL_BACKEND = 'django_ses.SESBackend'
+
+AWS_SES_REGION_NAME = 'eu-west-1'
+AWS_SES_REGION_ENDPOINT = 'email.eu-west-1.amazonaws.com'
+
+EMAIL_HOST = CFG['aws_smtp']
+EMAIL_PORT = CFG['aws_port']
+EMAIL_HOST_USER = CFG['aws_smtp_username']
+EMAIL_HOST_PASSWORD = CFG['aws_smtp_password']
EMAIL_USE_TLS = CFG['email_use_tls']
-DEFAULT_FROM_EMAIL = 'admin@rowsandall.com'
+DEFAULT_FROM_EMAIL = 'info@rowsandall.com'
# weather stuff