def test_emails_arent_sent_to_author(self): """ We want to make sure that when a user creates or changes an item they are not sent an email. The email goes to those that do not already know the item has changed! """ andy = User.objects.create_user("Andy", "*****@*****.**", password='******') billy = User.objects.create_user("Billy", "*****@*****.**", password='******') chris = User.objects.create_user("Chris", "*****@*****.**", password='******') decision = Decision(description='Test', status=0) decision.save(andy) #billy decides he wants to watch... decision.watchers = [billy] #andy changes the content mymail = OpenConsentEmailMessage('content_change', decision) #only watchers get mail, not the author self.assertNotIn(andy.email, mymail.to) self.assertIn(billy.email, mymail.to) self.assertNotIn(chris.email, mymail.to)
def test_emails_dont_contain_escaped_characters(self): """ We want to verify that the emails sent out do not contain confusing text like '&' instead of '&' or ''<' instead of '<' All plaintext emails should be marked 'safe' in the Django template. """ decision = Decision(description='&', status=0) decision.save(self.user) mymail = OpenConsentEmailMessage('new', decision) self.assertNotIn('&', mymail.subject) self.assertNotIn('&', mymail.body) mymail = OpenConsentEmailMessage('status_change', decision, old_obj=decision) self.assertNotIn('&', mymail.subject) self.assertNotIn('&', mymail.body) mymail = OpenConsentEmailMessage('content_change', decision) self.assertNotIn('&', mymail.subject) self.assertNotIn('&', mymail.body)
def test_model_feedbackcount_changes(self): decision = Decision(description="Decision test data") decision.save(self.user) self.instance_attribute_has_value(decision, "feedbackcount", 0) feedback = Feedback(description="Feedback test data", decision=decision) feedback.save() self.instance_attribute_has_value(decision, "feedbackcount", 1)
def test_emails_dont_contain_escaped_characters(self): """ We want to verify that the emails sent out do not contain confusing text like '&' instead of '&' or ''<' instead of '<' All plaintext emails should be marked 'safe' in the Django template. """ decision = Decision(description='&', status=0) decision.save(self.user) mymail = OpenConsentEmailMessage('new', decision) self.assertNotIn('&', mymail.subject) self.assertNotIn('&', mymail.body) mymail = OpenConsentEmailMessage('status_change', decision, old_object=decision) self.assertNotIn('&', mymail.subject) self.assertNotIn('&', mymail.body) mymail = OpenConsentEmailMessage('content_change', decision) self.assertNotIn('&', mymail.subject) self.assertNotIn('&', mymail.body)
def create_and_return_decision(self, description='Decision Time', status=Decision.PROPOSAL_STATUS, deadline=now().date()): decision = Decision(description=description, status=status, organization=self.bettysorg, deadline=deadline) decision.author = self.user decision.save() return decision
def create_and_return_decision(self, description='Decision Time', status=Decision.PROPOSAL_STATUS): decision = Decision(description=description, status=status) decision.save(self.user) return decision
def test_urlize(self): decision = Decision(description="text www.google.com text") decision.save() path = reverse('publicweb_decision_detail', args=[decision.id]) response = self.client.get(path) self.assertContains(response, '<a href="http://www.google.com" rel="nofollow">www.google.com</a>', 1, msg_prefix="Failed to urlize text")
def test_decision_linebreaks(self): decision = Decision(description="text\ntext") decision.save() path = reverse('publicweb_decision_detail', args=[decision.id]) response = self.client.get(path) self.assertContains(response, 'text<br />text', 1, msg_prefix="Failed to line break text")
def create_and_return_decision(self, description='Decision Time', status=Decision.PROPOSAL_STATUS): decision = Decision(description=description, status=status) decision.author = self.user decision.save() return decision
def test_model_feedbackcount_changes(self): decision = Decision(description="Decision test data") decision.save(self.user) self.instance_attribute_has_value(decision,"feedbackcount",0) feedback = Feedback(description="Feedback test data", decision=decision) feedback.save() self.instance_attribute_has_value(decision,"feedbackcount",1)
def test_add_feedback(self): decision = Decision(status=Decision.PROPOSAL_STATUS, description='Make Eggs') decision.save() post_dict= {'rating': '2', 'description': 'The eggs are bad'} response = self.client.post(reverse('publicweb_feedback_create', args=[decision.id]), post_dict, follow=True ) feedback = decision.feedback_set.all()[:1].get() self.assertEquals('The eggs are bad', feedback.description)
def test_feedback_statistics(self): decision = Decision(description="Decision test data") self.model_has_attribute(decision, "get_feedback_statistics") statistics = decision.get_feedback_statistics() self.assertTrue("consent" in statistics) self.assertTrue("concern" in statistics) self.assertTrue("danger" in statistics) self.assertTrue("question" in statistics) self.assertTrue("comment" in statistics)
def test_feedback_author_is_assigned(self): decision = Decision(description="Test decision") decision.save() path = reverse('publicweb_feedback_create', args=[decision.id]) post_dict = {'description': 'Lorem Ipsum','rating': Feedback.COMMENT_STATUS } response = self.client.post(path, post_dict) self.assertRedirects(response,reverse('publicweb_item_detail', args=[decision.id])) feedback = decision.feedback_set.get() self.assertEqual(feedback.author, self.user)
def test_feedback_linebreaks(self): decision = Decision(description="Lorem") decision.save() feedback = Feedback(description="text\ntext") feedback.decision = decision feedback.save() path = reverse('publicweb_feedback_detail', args=[feedback.id]) response = self.client.get(path) self.assertContains(response, 'text<br />text', 1, msg_prefix="Failed to line break text")
def assert_list_page_sorted_by_date_column(self, column): # Create test decisions in reverse date order. decision = Decision(description="Decision None 1", status=Decision.DECISION_STATUS) decision.save(self.user) for i in range(5, 0, -1): decision = Decision(description='Decision %d' % i, status=Decision.DECISION_STATUS) setattr(decision, column, datetime.date(2001, 3, i)) decision.save(self.user) decision = Decision(description="Decision None 2", status=Decision.DECISION_STATUS) decision.save(self.user) #note that we don't actually have to _display_ the field to sort bny it response = self.client.get(reverse('publicweb_item_list', args=['decision']), dict(sort=column)) object_list = response.context['object_list'] for i in range(1, 6): self.assertEquals(datetime.date(2001, 3, i), getattr(object_list[i-1], column)) self.assertEquals(None, getattr(object_list[5], column)) self.assertEquals(None, getattr(object_list[6], column)) Decision.objects.all().delete()
def test_list_page_sorted_by_watchers(self): adam = User.objects.get(username='******') barry = User.objects.get(username='******') charlie = User.objects.get(username='******') decision1 = Decision(description="Apple", status=Decision.DECISION_STATUS) decision1.save(self.user) decision1.watchers.add(barry) decision1.watchers.add(charlie) decision2 = Decision(description="Coconut", status=Decision.DECISION_STATUS) decision2.save() decision3 = Decision(description="Blackberry", status=Decision.DECISION_STATUS) decision3.save(self.user) decision3.watchers.add(barry) response = self.client.get(reverse('publicweb_item_list', args=['decision']), dict(sort='watchers')) object_list = response.context['object_list'] self.assertEquals(decision1.id, getattr(object_list[0], 'id')) self.assertEquals(decision3.id, getattr(object_list[1], 'id')) self.assertEquals(decision2.id, getattr(object_list[2], 'id'))
def test_list_page_sorted_by_feedback(self): # Create test decisions in reverse date order. decision1 = Decision(description="Apple", status=Decision.DECISION_STATUS) decision1.save(self.user) feedback = Feedback(description="One", decision=decision1) feedback.save() feedback = Feedback(description="Two", decision=decision1) feedback.save() feedback = Feedback(description="Three", decision=decision1) feedback.save() decision2 = Decision(description="Coconut", status=Decision.DECISION_STATUS) decision2.save() decision3 = Decision(description="Blackberry", status=Decision.DECISION_STATUS) decision3.save(self.user) feedback = Feedback(description="One", decision=decision3) feedback.save() feedback = Feedback(description="Two", decision=decision3) feedback.save() response = self.client.get(reverse('publicweb_item_list', args=['decision']), dict(sort='feedback')) object_list = response.context['object_list'] self.assertEquals(decision1.id, getattr(object_list[0], 'id')) self.assertEquals(decision3.id, getattr(object_list[1], 'id')) self.assertEquals(decision2.id, getattr(object_list[2], 'id'))
def test_decisions_can_be_sorted_by_id(self): id_list = [] for i in range(5, 0, -1): decision = Decision(description='Decision %d' % i) decision.save(self.user) id_list.append(decision.id) response = self.client.get(reverse('publicweb_item_list', args=['proposal']), {'sort':'id'}) object_list = response.context['object_list'] for i in range(1, 6): self.assertEquals(id_list[i-1], object_list[i-1].id)
def test_feedback_author_shown(self): self.user = self.login('Barry') decision = Decision(description="Lorem Ipsum") decision.save() feedback = Feedback(description="Dolor sit") feedback.author = self.user feedback.decision = decision feedback.save() self.user = self.login('Adam') path = reverse('publicweb_item_detail', args=[decision.id]) response = self.client.get(path) barry = User.objects.get(username='******') self.assertContains(response, barry.username)
def assert_decisions_sorted_by_date_column(self, column): # Create test decisions in reverse date order. for i in range(5, 0, -1): decision = Decision(description='Decision %d' % i, status=Decision.DECISION_STATUS) setattr(decision, column, datetime.date(2001, 3, i)) decision.save(self.user) response = self.client.get(reverse('publicweb_item_list', args=['decision']), dict(sort=column)) object_list = response.context['object_list'] for i in range(1, 6): self.assertEquals(datetime.date(2001, 3, i), getattr(object_list[i-1], column))
def test_decisions_can_be_sorted_by_id(self): id_list = [] for i in range(5, 0, -1): decision = Decision(description='Decision %d' % i) decision.save(self.user) id_list.append(decision.id) response = self.client.get(reverse('list', args=['proposal']), {'sort': 'id'}) object_list = response.context['object_list'] for i in range(1, 6): self.assertEquals(id_list[i - 1], object_list[i - 1].id)
def assert_decisions_sorted_by_date_column(self, column): # Create test decisions in reverse date order. for i in range(5, 0, -1): decision = Decision(description='Decision %d' % i, status=Decision.DECISION_STATUS) setattr(decision, column, datetime.date(2001, 3, i)) decision.save(self.user) response = self.client.get(reverse('list', args=['decision']), dict(sort=column)) object_list = response.context['object_list'] for i in range(1, 6): self.assertEquals(datetime.date(2001, 3, i), getattr(object_list[i - 1], column))
def test_status_is_set_in_decision_detail_context(self): """ Same as test_status_is_set_in_decision_list_context but for decision_detail view. """ dd = DecisionDetail() manual_status = 'i set the status' decision = Decision(status=manual_status, organization=Organization()) dd.object = decision context = dd.get_context_data() self.assertEqual(context['tab'], manual_status)
def test_save_when_no_author(self): decision = Decision(description="Test", status=0) decision.author = None decision.save() decision = Decision.objects.get() decision.description = "A change." try: decision.save() except: self.fail("Failed to save object.")
def _process_email(self, mail, verbosity): # pylint: disable=R0914 logger = logging.getLogger('econsensus') #handle multipart mails, cycle through mail #until find text type with a full payload. if mail.is_multipart(): for message in mail.get_payload(): if message.get_content_maintype() == 'text': msg_string = self._strip_string(message.get_payload(), verbosity) if msg_string: break else: msg_string = self._strip_string(mail.get_payload(), verbosity) if not msg_string: logger.error("[EMAIL REJECTED] From '%s' Reason: Email payload empty" % mail['From']) return #Must match email 'from' address to user from_match = re.search('([\w\-\.]+@\w[\w\-]+\.+[\w\-]+)', mail['From']) if from_match: self._print_if_verbose(verbosity, "Found email 'from' '%s'" % from_match.group(1)) try: user = User.objects.get(email=from_match.group(1)) self._print_if_verbose(verbosity, "Matched email to user '%s'" % user) except: logger.error("[EMAIL REJECTED] From '%s' Reason: Email address does not correspond to any known User" % mail['From']) return else: logger.error("[EMAIL REJECTED] From '%s' Reason: Unrecognised email address format" % mail['From']) return #Must match email 'to' address to organization org_match = re.search('([\w\-\.]+)@\w[\w\-]+\.+[\w\-]+', mail['To']) if org_match: self._print_if_verbose(verbosity, "Found email 'to' '%s'" % org_match.group(1)) try: organization = Organization.objects.get(slug=org_match.group(1)) self._print_if_verbose(verbosity, "Matched email to organization '%s'" % organization.name) except: logger.error("[EMAIL REJECTED] From '%s' Reason: '%s' does not correspond to any known Organization" \ % (mail['From'], org_match.group(1))) return else: logger.error("[EMAIL REJECTED] From '%s' Reason: Couldn't pull Organization from '%s'" % (mail['From'], mail['To'])) return #User must be a member of the Organization if organization not in Organization.active.get_for_user(user): self._print_if_verbose(verbosity, "User %s is not a member of Organization %s" % (user.username, organization.name)) logger.error("[EMAIL REJECTED] From '%s' Reason: User '%s' is not a member of Organization '%s'" \ % (mail['From'], user.username, organization.name)) return #Look for feedback types in the message body rating = Feedback.COMMENT_STATUS description = msg_string parse_feedback = re.match('(\w+)\s*:\s*([\s\S]*)', msg_string, re.IGNORECASE) if parse_feedback: description = parse_feedback.group(2) rating_match = re.match('question|danger|concerns|consent|comment', parse_feedback.group(1), re.IGNORECASE) if rating_match: self._print_if_verbose(verbosity, "Found feedback rating '%s'" % rating_match.group()) rating = rating_int(rating_match.group().lower()) # Determine whether email is in reply to a notification subject_match = re.search('\[(\d+)(?:\\\\(\d+)(?:\\\\(\d+))?)?\]', mail['Subject']) if subject_match: #process comment or feedback against feedback if subject_match.group(2): self._print_if_verbose(verbosity, "Found feedback id '%s' in Subject" % subject_match.group(2)) try: feedback = Feedback.objects.get(pk=subject_match.group(2)) except: logger.error("[EMAIL REJECTED] From '%s' Reason: id '%s' does not correspond to any known Feedback" \ % (mail['From'], subject_match.group(2))) return if parse_feedback and rating_match: decision = feedback.decision self._print_if_verbose(verbosity, "Creating feedback with rating '%s' and description '%s'." % (rating, description)) feedback = Feedback(author=user, decision=decision, rating=rating, description=description) feedback.save() logger.info("User '%s' added feedback via email to decision #%s" % (user, decision.id)) self._print_if_verbose(verbosity, "Found corresponding object '%s'" % decision.excerpt) else: comment_text = msg_string self._print_if_verbose(verbosity, "Creating comment '%s'." % (comment_text)) comment = Comment(user=user, comment = comment_text, content_object=feedback, object_pk=feedback.id, content_type=ContentType.objects.get(app_label="publicweb", model="feedback"), submit_date = timezone.now(), site = Site.objects.get_current()) comment.save() logger.info("User '%s' added comment via email to feedback #%s" % (user, feedback.id)) self._print_if_verbose(verbosity, "Found corresponding object '%s'" % feedback.description) #process feedback against decision elif subject_match.group(1): self._print_if_verbose(verbosity, "Found decision id '%s' in Subject" % subject_match.group(1)) try: decision = Decision.objects.get(pk=subject_match.group(1)) except: logger.error("[EMAIL REJECTED] From '%s' Reason: id '%s' does not correspond to any known Decision" \ % (mail['From'], subject_match.group(1))) return self._print_if_verbose(verbosity, "Creating feedback with rating '%s' and description '%s'." % (rating, description)) feedback = Feedback(author=user, decision=decision, rating=rating, description=description) feedback.save() logger.info("User '%s' added feedback via email to decision #%s" % (user, decision.id)) self._print_if_verbose(verbosity, "Found corresponding object '%s'" % decision.excerpt) else: self._print_if_verbose(verbosity, "No id found in message subject: %s" % mail['Subject']) logger.error("[EMAIL REJECTED] From '%s' Reason: No id present." \ % mail['From']) # Email was not in reply to a notification so create a new proposal else: proposal_match = re.search('proposal', mail['Subject'], re.IGNORECASE) if proposal_match: decision = Decision(author=user, editor=user, status=Decision.PROPOSAL_STATUS, organization=organization, \ description=msg_string) decision.save() self._print_if_verbose(verbosity, "User '%s' created decision #%s via email" % (user, decision.id)) logger.info("User '%s' created decision #%s via email" % (user, decision.id)) else: logger.error("[EMAIL REJECTED] From '%s' Reason: Email was not in reply to a notification and body didn't contain keyword 'proposal'" \ % mail['From'])
def test_watchercount_changes(self): decision = Decision(description="Decision test data") decision.save(self.user) decision.add_watcher(self.user) self.assertEqual(1, decision.watchercount())
def test_list_page_sorted_by_description(self): # Create test decisions in reverse date order. decision = Decision(description="Apple", status=Decision.DECISION_STATUS) decision.save(self.user) decision = Decision(description="Dandelion", status=Decision.DECISION_STATUS) decision.save(self.user) decision = Decision(description="Blackberry", status=Decision.DECISION_STATUS) decision.save(self.user) decision = Decision(description="Coconut", status=Decision.DECISION_STATUS) decision.save(self.user) response = self.client.get(reverse('publicweb_item_list', args=['decision']), dict(sort='description')) object_list = response.context['object_list'] self.assertEquals("Apple", getattr(object_list[0], 'description')) self.assertEquals("Blackberry", getattr(object_list[1], 'description')) self.assertEquals("Coconut", getattr(object_list[2], 'description')) self.assertEquals("Dandelion", getattr(object_list[3], 'description'))
def test_decision_has_feedbackcount(self): decision = Decision(description="Decision test data") self.model_has_attribute(decision, "feedbackcount")
def test_decision_has_archived_date(self): decision = Decision(description="Decision test data") self.model_has_attribute(decision, "archived_date")
def test_feedback_can_have_empty_description(self): decision = Decision(description='Test', status=Decision.DECISION_STATUS) decision.save(self.user) feedback = Feedback(rating=Feedback.CONSENT_STATUS, decision=decision) self.instance_validates(feedback)
def _process_email(self, mail, verbosity): # pylint: disable=R0914 logger = logging.getLogger('econsensus') #handle multipart mails, cycle through mail #until find text type with a full payload. if mail.is_multipart(): for message in mail.get_payload(): if message.get_content_maintype() == 'text': msg_string = self._strip_string(message.get_payload(), verbosity) if msg_string: break else: msg_string = self._strip_string(mail.get_payload(), verbosity) if not msg_string: logger.error( "[EMAIL REJECTED] From '%s' Reason: Email payload empty" % mail['From']) return #Must match email 'from' address to user from_match = re.search('([\w\-\.]+@\w[\w\-]+\.+[\w\-]+)', mail['From']) if from_match: self._print_if_verbose( verbosity, "Found email 'from' '%s'" % from_match.group(1)) try: user = User.objects.get(email=from_match.group(1)) except ObjectDoesNotExist: logger.error("[EMAIL REJECTED] From '%s' Reason: id '%s' does not correspond to any known User" \ % (mail['From'], from_match.group(1))) return except MultipleObjectsReturned: logger.error("[EMAIL REJECTED] From '%s' Reason: Query returned several Users for id '%s'" \ % (mail['From'], from_match.group(1))) return self._print_if_verbose(verbosity, "Matched email to user '%s'" % user) else: logger.error( "[EMAIL REJECTED] From '%s' Reason: Unrecognised email address format" % mail['From']) return #Must match email 'to' address to organization org_match = re.search('([\w\-\.]+)@\w[\w\-]+\.+[\w\-]+', mail['To']) if org_match: self._print_if_verbose( verbosity, "Found email 'to' '%s'" % org_match.group(1)) try: organization = Organization.objects.get( slug=org_match.group(1)) except ObjectDoesNotExist: logger.error("[EMAIL REJECTED] From '%s' Reason: id '%s' does not correspond to any known Organization" \ % (mail['From'], org_match.group(1))) return except MultipleObjectsReturned: logger.error("[EMAIL REJECTED] From '%s' Reason: Query returned several Organizations for id '%s'" \ % (mail['From'], org_match.group(1))) return self._print_if_verbose( verbosity, "Matched email to organization '%s'" % organization.name) else: logger.error( "[EMAIL REJECTED] From '%s' Reason: Couldn't pull Organization from '%s'" % (mail['From'], mail['To'])) return #User must be a member of the Organization if organization not in Organization.active.get_for_user(user): self._print_if_verbose( verbosity, "User %s is not a member of Organization %s" % (user.username, organization.name)) logger.error("[EMAIL REJECTED] From '%s' Reason: User '%s' is not a member of Organization '%s'" \ % (mail['From'], user.username, organization.name)) return #Look for feedback types in the message body rating = Feedback.COMMENT_STATUS description = msg_string parse_feedback = re.match('(\w+)\s*:\s*([\s\S]*)', msg_string, re.IGNORECASE) if parse_feedback: description = parse_feedback.group(2) rating_match = re.match('question|danger|concerns|consent|comment', parse_feedback.group(1), re.IGNORECASE) if rating_match: self._print_if_verbose( verbosity, "Found feedback rating '%s'" % rating_match.group()) rating = dict(Feedback.RATING_CHOICES).values().index( rating_match.group().lower()) # Determine whether email is in reply to a notification subject_match = re.search('\[EC#(\d+)(?:\\\\(\d+)(?:\\\\(\d+))?)?\]', mail['Subject']) if subject_match: #Check that the user has the right to comment against the decision. if subject_match.group(1): self._print_if_verbose( verbosity, "Found decision id '%s' in Subject" % subject_match.group(1)) try: decision = Decision.objects.get(pk=subject_match.group(1)) except ObjectDoesNotExist: logger.error("[EMAIL REJECTED] From '%s' Reason: id '%s' does not correspond to any known Decision" \ % (mail['From'], subject_match.group(1))) return except MultipleObjectsReturned: logger.error("[EMAIL REJECTED] From '%s' Reason: Query returned several Decisions for id '%s'" \ % (mail['From'], subject_match.group(1))) return if user not in decision.organization.users.all(): logger.error("[EMAIL REJECTED] From '%s' Reason: User cannot reply to decision #%s because they are not a member of that organization." \ % (mail['From'], subject_match.group(1))) return #process comment or feedback against feedback if subject_match.group(2): self._print_if_verbose( verbosity, "Found feedback id '%s' in Subject" % subject_match.group(2)) try: feedback = Feedback.objects.get(pk=subject_match.group(2)) except ObjectDoesNotExist: logger.error("[EMAIL REJECTED] From '%s' Reason: id '%s' does not correspond to any known Feedback" \ % (mail['From'], subject_match.group(2))) return except MultipleObjectsReturned: logger.error("[EMAIL REJECTED] From '%s' Reason: Query returned more than one Feedback for id '%s'" \ % (mail['From'], subject_match.group(2))) return if parse_feedback and rating_match: decision = feedback.decision self._print_if_verbose( verbosity, "Creating feedback with rating '%s' and description '%s'." % (rating, description)) feedback = Feedback(author=user, decision=decision, rating=rating, description=description) feedback.save() logger.info( "User '%s' added feedback via email to decision #%s" % (user, decision.id)) self._print_if_verbose( verbosity, "Found corresponding object '%s'" % decision.excerpt) else: comment_text = msg_string self._print_if_verbose( verbosity, "Creating comment '%s'." % (comment_text)) comment = Comment(user=user, user_name=user.get_full_name(), user_email=user.email, comment=comment_text, content_object=feedback, object_pk=feedback.id, content_type=ContentType.objects.get( app_label="publicweb", model="feedback"), submit_date=timezone.now(), site=Site.objects.get_current()) comment.save() logger.info( "User '%s' added comment via email to feedback #%s" % (user, feedback.id)) self._print_if_verbose( verbosity, "Found corresponding object '%s'" % feedback.description) #process feedback against decision elif subject_match.group(1): self._print_if_verbose( verbosity, "Creating feedback with rating '%s' and description '%s'." % (rating, description)) feedback = Feedback(author=user, decision=decision, rating=rating, description=description) feedback.save() logger.info( "User '%s' added feedback via email to decision #%s" % (user, decision.id)) self._print_if_verbose( verbosity, "Found corresponding object '%s'" % decision.excerpt) else: self._print_if_verbose( verbosity, "No id found in message subject: %s" % mail['Subject']) logger.error("[EMAIL REJECTED] From '%s' Reason: No id present." \ % mail['From']) # Email was not in reply to a notification so create a new proposal else: proposal_match = re.search('proposal', mail['Subject'], re.IGNORECASE) if proposal_match: decision = Decision(author=user, editor=user, status=Decision.PROPOSAL_STATUS, organization=organization, \ description=msg_string) decision.save() self._print_if_verbose( verbosity, "User '%s' created decision #%s via email" % (user, decision.id)) logger.info("User '%s' created decision #%s via email" % (user, decision.id)) else: logger.error("[EMAIL REJECTED] From '%s' Reason: Email was not in reply to a notification and body didn't contain keyword 'proposal'" \ % mail['From'])
def _process_email(self, mail, verbosity): # pylint: disable=R0914 user = None decision = None user_found = False object_found = False org_found = False msg_string = '' #match email 'from' address to user from_match = re.search('([\w\-\.]+@\w[\w\-]+\.+[\w\-]+)', mail['From']) if from_match: self._print_if_verbose(verbosity, "Found email 'from' '%s'" % from_match.group(1)) try: user = User.objects.get(email=from_match.group(1)) user_found = True self._print_if_verbose(verbosity, "Matched email to user '%s'" % user) except: pass #match id to object id_match = re.search('#(\d+)', mail['Subject']) if id_match: self._print_if_verbose(verbosity, "Found '%s' in Subject" % id_match.group()) try: decision = Decision.objects.get(pk=id_match.group(1)) object_found = True self._print_if_verbose(verbosity, "Found corresponding object '%s'" % decision.excerpt) except: pass #match email 'to' address to organization to_match = re.search('([\w\-\.]+)@\w[\w\-]+\.+[\w\-]+', mail['To']) if to_match: self._print_if_verbose(verbosity, "Found email 'to' '%s'" % to_match.group(1)) try: organization = Organization.objects.get(slug=to_match.group(1)) org_found = True self._print_if_verbose(verbosity, "Matched email to organization '%s'" % organization.name) except: pass proposal_found = re.search('proposal', mail['Subject'], re.IGNORECASE) #handle multipart mails, cycle through mail #until find text type with a full payload. if mail.is_multipart(): for message in mail.get_payload(): if message.get_content_maintype() == 'text': msg_string = self._strip_string(message.get_payload(), verbosity) if msg_string: break else: msg_string = self._strip_string(mail.get_payload(), verbosity) if user_found and msg_string: if object_found: parse_feedback = re.match('(\w+)\s*:\s*(\w+[\s\w]*)', msg_string, re.IGNORECASE) if parse_feedback: description = parse_feedback.group(2) rating_match = re.match('question|danger|concerns|consent|comment', parse_feedback.group(1), re.IGNORECASE) else: rating_match = None description = msg_string if rating_match: self._print_if_verbose(verbosity, "Found feedback rating '%s'" % rating_match.group()) rating = rating_int(rating_match.group().lower()) else: rating = Feedback.COMMENT_STATUS self._print_if_verbose(verbosity, "Creating feedback with rating '%s' and description '%s'." % (rating, description)) feedback = Feedback(author=user, decision=decision, rating=rating, description=description) feedback.save() elif proposal_found and org_found: self._print_if_verbose(verbosity, "No matching object, creating proposal") if organization in Organization.active.get_for_user(user): decision = Decision(author=user, editor=user, status=Decision.PROPOSAL_STATUS, organization=organization, description=msg_string) decision.save() else: self._print_if_verbose(verbosity, "User %s is not a member of Organization %s" % (user.username, organization.name))