Exemplo n.º 1
0
    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)
Exemplo n.º 2
0
    def test_emails_dont_contain_escaped_characters(self):
        """
        We want to verify that the emails sent out do not contain
        confusing text like '&amp' instead of '&' or ''&lt'
        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('&amp', mymail.subject)
        self.assertNotIn('&amp', mymail.body)

        mymail = OpenConsentEmailMessage('status_change',
                                         decision,
                                         old_obj=decision)

        self.assertNotIn('&amp', mymail.subject)
        self.assertNotIn('&amp', mymail.body)

        mymail = OpenConsentEmailMessage('content_change', decision)

        self.assertNotIn('&amp', mymail.subject)
        self.assertNotIn('&amp', mymail.body)
Exemplo n.º 3
0
 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)       
Exemplo n.º 4
0
    def test_emails_dont_contain_escaped_characters(self):
        """
        We want to verify that the emails sent out do not contain
        confusing text like '&amp' instead of '&' or ''&lt'
        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('&amp', mymail.subject)
        self.assertNotIn('&amp', mymail.body)

        mymail = OpenConsentEmailMessage('status_change', decision, old_object=decision)
        
        self.assertNotIn('&amp', mymail.subject)
        self.assertNotIn('&amp', mymail.body)
        
        mymail = OpenConsentEmailMessage('content_change', decision)
        
        self.assertNotIn('&amp', mymail.subject)
        self.assertNotIn('&amp', mymail.body)
Exemplo n.º 5
0
 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
Exemplo n.º 6
0
    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
Exemplo n.º 7
0
 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")
Exemplo n.º 8
0
 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")
Exemplo n.º 9
0
 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
Exemplo n.º 10
0
 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)
Exemplo n.º 11
0
 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)
Exemplo n.º 12
0
 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)
Exemplo n.º 13
0
 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)
     
Exemplo n.º 14
0
 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")
Exemplo n.º 15
0
    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()
Exemplo n.º 16
0
    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')) 
Exemplo n.º 17
0
    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')) 
Exemplo n.º 18
0
    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
Exemplo n.º 19
0
 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)
Exemplo n.º 20
0
 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)
Exemplo n.º 21
0
 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))
Exemplo n.º 22
0
    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)
Exemplo n.º 23
0
    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))
Exemplo n.º 24
0
 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)
Exemplo n.º 25
0
 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.")
Exemplo n.º 26
0
    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)
Exemplo n.º 27
0
    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'])
Exemplo n.º 28
0
 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())
Exemplo n.º 29
0
    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'))
Exemplo n.º 30
0
 def test_decision_has_feedbackcount(self):
     decision = Decision(description="Decision test data")
     self.model_has_attribute(decision, "feedbackcount")
Exemplo n.º 31
0
 def test_decision_has_archived_date(self):
     decision = Decision(description="Decision test data")
     self.model_has_attribute(decision, "archived_date")
Exemplo n.º 32
0
 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)
Exemplo n.º 33
0
    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'])
Exemplo n.º 34
0
    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))