diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py index 96e39eb8..6835e089 100644 --- a/rowers/management/commands/processemail.py +++ b/rowers/management/commands/processemail.py @@ -235,6 +235,13 @@ class Command(BaseCommand): rowers = [ r for r in Rower.objects.all() if r.user.email.lower() == from_address ] + try: + rowers2 = [ + r for r in Rower.objects.all() if from_address in r.emailalternatives + ] + rowers = rowers+rowers2 + except TypeError: + pass except IOError: rowers = [] except Message.DoesNotExist: diff --git a/rowers/models.py b/rowers/models.py index 0471b72f..c302b3ad 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -131,6 +131,56 @@ class TemplateListField(models.TextField): value = self._get_val_from_obj(obj) return self.get_deb_prep_value(value) +# model for Emails field +class AlternativeEmails(models.TextField): + def __init__(self, *args, **kwargs): + self.token = kwargs.pop('token',',') + super(AlternativeEmails, self).__init__(*args,**kwargs) + + def to_python(self, value): + if not value: return + if isinstance(value, list): + return value + # remove double quotes and brackets + 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) + + return value.split(self.token) + + def from_db_value(self,value, expression, connection): + if value is None: + return value + if isinstance(value, list): + return value + return value.split(self.token) + + def get_db_prep_value(self, value, connection, prepared=False): + if not value: return + assert(isinstance(value, list) or isinstance(value, tuple)) + newlist = [] + for s in value: + + try: + validate_email(s) + newlist.append(s) + except ValidationError: + pass + + return self.token.join([str(s) for s in newlist]) + + def value_to_string(self, obj): + value = self._get_val_from_obj(obj) + return self.get_deb_prep_value(value) + # model for Power Zone names class PowerZonesField(models.TextField): # __metaclass__ = models.SubfieldBase @@ -804,6 +854,8 @@ class Rower(models.Model): 'Pwr TR', 'Pwr AN']) + emailalternatives = AlternativeEmails(default=[],null=True,blank=True,verbose_name='Alternative Email addresses (separate with ",")') + # Site Settings workflowleftpanel = TemplateListField(default=defaultleft) workflowmiddlepanel = TemplateListField(default=defaultmiddle) @@ -3677,7 +3729,7 @@ class AccountRowerForm(ModelForm): 'getimportantemails', 'defaulttimezone','showfavoritechartnotes', 'defaultlandingpage', - 'offercoaching','autojoin'] + 'offercoaching','autojoin','emailalternatives'] widgets = { 'birthdate': SelectDateWidget( @@ -3686,10 +3738,31 @@ class AccountRowerForm(ModelForm): } def __init__(self, *args, **kwargs): + super(AccountRowerForm, self).__init__(*args, **kwargs) if 'coach' not in self.instance.rowerplan: self.fields.pop('offercoaching') + try: + self.initial['emailalternatives'] = ', '.join(self.instance.emailalternatives) + except TypeError: + pass + + def clean(self): + cd = self.cleaned_data + z = "".join(cd['emailalternatives'].split()).split(',') + emailalternatives = [] + for addr in z: + try: + validate_email(addr) + match = User.objects.filter(email__iexact=addr) + if match.count() == 0: + emailalternatives.append(addr) + except ValidationError: + pass + + self.cleaned_data['emailalternatives'] = emailalternatives + # Form to set static chart settings class StaticChartRowerForm(ModelForm): class Meta: diff --git a/rowers/tests/test_emails.py b/rowers/tests/test_emails.py index 11149be0..eca8a37c 100644 --- a/rowers/tests/test_emails.py +++ b/rowers/tests/test_emails.py @@ -12,9 +12,12 @@ class EmailUpload(TestCase): self.c = Client() u = User.objects.create_user('john', 'sander@ds.ds', - 'koeinsloot') + 'koeinsloot', + first_name='John', + last_name='Sloot') r = Rower.objects.create(user=u,gdproptin=True,surveydone=True, - gdproptindate=timezone.now() + gdproptindate=timezone.now(), + emailalternatives=['sander2@ds.nl'] ) self.theadmin = UserFactory(is_staff=True) @@ -76,6 +79,33 @@ workout run self.assertEqual(w.name,'test') self.assertEqual(w.notes,'aap noot mies') + + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db) + def test_uploadapi2(self,mocked_sqlalchemy,mocked_getsmallrowdata_db): + form_data = { + 'title': 'test', + 'workouttype':'rower', + 'boattype': '1x', + 'notes': 'aap noot mies', + 'make_plot': False, + 'upload_to_C2': False, + 'plottype': 'timeplot', + 'file': 'media/mailbox_attachments/colin3.csv', + 'secret': settings.UPLOAD_SERVICE_SECRET, + 'useremail': 'sander2@ds.nl', + } + + url = reverse('workout_upload_api') + response = self.c.post(url,form_data,HTTP_HOST='127.0.0.1:4533') + self.assertEqual(response.status_code,200) + + # should also test if workout is created + w = Workout.objects.get(id=1) + self.assertEqual(w.name,'test') + self.assertEqual(w.notes,'aap noot mies') + @patch('rowers.dataprep.create_engine') @patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db) def test_uploadapi_credentials(self,mocked_sqlalchemy,mocked_getsmallrowdata_db): diff --git a/rowers/views/userviews.py b/rowers/views/userviews.py index 88e3a9c0..caa61060 100644 --- a/rowers/views/userviews.py +++ b/rowers/views/userviews.py @@ -415,6 +415,7 @@ def rower_edit_view(request,rowerid=0,userid=0,message=""): u.email = email resetbounce = True + emailalternatives = cd['emailalternatives'] u.save() r.defaulttimezone=defaulttimezone @@ -428,6 +429,8 @@ def rower_edit_view(request,rowerid=0,userid=0,message=""): r.sex = sex r.birthdate = birthdate r.autojoin = autojoin + r.emailalternatives = emailalternatives + if resetbounce and r.emailbounced: r.emailbounced = False diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 16ee013e..4bcd3e23 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -4685,17 +4685,25 @@ def workout_upload_api(request): if rowerform.is_valid(): u = rowerform.cleaned_data['user'] r = getrower(u) - elif 'useremail' in post_data: + else: + message = {'status':'false','message':'invalid user'} + return JSONResponse(status=400,data=message) + + if 'useremail' in post_data: us = User.objects.filter(email=post_data['useremail']) if len(us): u = us[0] r = getrower(u) else: - message = {'status':'false','message':'could not find user'} - return JSONResponse(status=400,data=message) - else: - message = {'status':'false','message':'invalid user'} - return JSONResponse(status=400,data=message) + r = None + for rwr in Rower.objects.all(): + if post_data['useremail'] in rwr.emailalternatives: + r = rwr + break + if post_data['useremail'] not in r.emailalternatives: + message = {'status':'false','message':'could not find user'} + return JSONResponse(status=400,data=message) + notes = form.cleaned_data['notes'] if optionsform.is_valid(): @@ -4712,6 +4720,9 @@ def workout_upload_api(request): message = optionsform.errors return JSONResponse(status=400,data=message) + if r is None: + message = {'status':'false','message':'something went wrong'} + return JSONResponse(status=400,data=message) id, message, f2 = dataprep.new_workout_from_file( r,f2,