Example #1
0
    def test_get_author_name(self):
        feedback = Feedback(author=None)
        self.assertEqual(feedback.get_author_name(), "An Anonymous Contributor")

        user = UserFactory()
        feedback = FeedbackFactory(author=user)
        self.assertEqual(feedback.get_author_name(), user.username)
Example #2
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)
Example #3
0
    def create_and_return_example_decision_with_feedback(self):
        decision = self.create_and_return_decision()

        feedback = Feedback(description='No time to decide', decision=decision)
        feedback.save()

        return decision
Example #4
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)       
 def create_and_return_example_concensus_decision_with_feedback(self):
     decision = self.create_and_return_decision(status=Decision.DECISION_STATUS)
     
     feedback = Feedback(description='No time to decide',
                       decision=decision)
     feedback.save()
     
     return decision
Example #6
0
    def test_get_author_name(self):
        feedback = Feedback(author=None)
        self.assertEqual(feedback.get_author_name(),
                         "An Anonymous Contributor")

        user = UserFactory()
        feedback = FeedbackFactory(author=user)
        self.assertEqual(feedback.get_author_name(), user.username)
Example #7
0
 def test_model_feedbackcount_changes(self):
     decision = self.make_decision()
     self.instance_attribute_has_value(decision, "feedbackcount", 0)
     feedback = Feedback(description="Feedback test data",
                         decision=decision,
                         author=self.user)
     feedback.save()
     self.instance_attribute_has_value(decision, "feedbackcount", 1)
Example #8
0
    def create_and_return_example_concensus_decision_with_feedback(self):
        decision = self.create_and_return_decision(
            status=Decision.DECISION_STATUS)

        feedback = Feedback(description='No time to decide', decision=decision)
        feedback.save()

        return decision
 def test_view_feedback(self):
     decision = self.create_and_return_decision()
     feedback = Feedback(description='test feedback',
                       decision=decision)
     feedback.save()
     response = self.client.get(reverse('publicweb_feedback_detail', args=[feedback.id]))
     self.assertContains(response, u"Feedback")
     self.assertContains(response, feedback.description)
 def create_and_return_example_decision_with_feedback(self):
     decision = self.create_and_return_decision()
     
     feedback = Feedback(description='No time to decide',
                       decision=decision)
     feedback.save()
     
     return decision
Example #11
0
 def test_feedback_linebreaks(self):
     decision = self.make_decision(description="Lorem")
     feedback = Feedback(description="text\ntext")
     feedback.decision = decision
     feedback.author = self.user
     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")
Example #12
0
 def test_view_feedback(self):
     decision = self.create_and_return_decision()
     feedback = Feedback(description='test feedback',
                         decision=decision,
                         author=self.user)
     feedback.save()
     response = self.client.get(
         reverse('publicweb_feedback_detail', args=[feedback.id]))
     self.assertContains(response, u"Feedback")
     self.assertContains(response, feedback.description)
Example #13
0
 def create_and_return_feedback(self,decision=None,
                                description='Feedback', author=None):
     if author==None:
         author=self.user
     if decision==None:
         decision=self.create_and_return_decision()
     feedback = Feedback(description=description,
                       decision=decision,
                       author=author)
     feedback.save()
     return feedback
Example #14
0
 def test_feedback_author_shown(self):
     decision = self.make_decision(description="Lorem Ipsum")
     feedback = Feedback(description="Dolor sit")
     feedback.author = self.user
     feedback.decision = decision
     feedback.save()
     
     self.user = self.login('charlie')        
     path = reverse('publicweb_item_detail', args=[decision.id])
     response = self.client.get(path)
     betty = User.objects.get(username='******')
     self.assertContains(response, betty.first_name)
Example #15
0
 def create_and_return_feedback(self,
                                decision=None,
                                description='Feedback',
                                author=None):
     if author == None:
         author = self.user
     if decision == None:
         decision = self.create_and_return_decision()
     feedback = Feedback(description=description,
                         decision=decision,
                         author=author)
     feedback.save()
     return feedback
Example #16
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)
Example #17
0
 def test_feedback_linebreaks(self):
     decision = self.make_decision(description="Lorem")
     feedback = Feedback(description="text\ntext")
     feedback.decision = decision
     feedback.author = self.user
     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")
Example #18
0
    def test_feedback_author_shown(self):
        decision = self.make_decision(description="Lorem Ipsum")
        feedback = Feedback(description="Dolor sit")
        feedback.author = self.user
        feedback.decision = decision
        feedback.save()

        self.user = self.login('charlie')
        path = reverse('publicweb_item_detail', args=[decision.id])
        response = self.client.get(path)
        betty = User.objects.get(username='******')
        self.assertContains(response, betty.first_name)
Example #19
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'])
    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')) 
Example #21
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)
Example #22
0
    def test_list_pages_can_be_sorted(self):
        """Test that sort works for all Decision List columns we offer it on"""
        number_of_test_decisions = 3  # Two additional empty decisions will be made

        # these are the dates we'll set in the test
        random_dates = [
            self._get_random_date() for i in range(number_of_test_decisions)
        ]
        random_descriptions = [
            self._get_random_string(30)
            for i in range(number_of_test_decisions)
        ]

        # set all the columns you want to test sorting on
        date_columns = [
            'deadline', 'decided_date', 'review_date', 'archived_date'
        ]

        #############################
        # Make the decisions
        #############################
        # Make an initial empty decision
        decisions = []
        decisions.append(
            self.make_decision(description="Decision None 1",
                               organization=self.bettysorg))

        # Create decisions with random data
        for i in range(number_of_test_decisions):
            d = self.make_decision(description=random_descriptions[i],
                                   organization=self.bettysorg)
            for column in date_columns:
                setattr(d, column, random_dates[i])
            d.save()
            decisions.append(d)

        # Set random feedback (offset by 1 so empty decision remains empty)
        for i in range(1, number_of_test_decisions + 1):
            for f in range(randint(1, 4)):
                Feedback(description=self._get_random_string(10),
                         decision=decisions[i],
                         author=self.user).save()

        # Make a final empty decision
        decisions.append(
            self.make_decision(description="Decision None 2",
                               organization=self.bettysorg))

        # Get the last_modified & id values
        last_modifieds = [decision.last_modified for decision in decisions]
        ids = [decision.id for decision in decisions]
        feedbackcounts = [decision.feedbackcount() for decision in decisions]
        excerpts = [decision.excerpt for decision in decisions]
        #############################

        # we need sorted values to compare against
        sorted_dates = sorted(random_dates)
        sorted_last_modifieds = sorted(last_modifieds)
        sorted_ids = sorted(ids)
        sorted_feedbackcounts = sorted(feedbackcounts)
        sorted_excerpts = sorted(excerpts, key=unicode.lower)

        # Test Dates
        for column in date_columns:
            response = self.client.get(
                reverse('publicweb_item_list',
                        args=[self.bettysorg.slug, 'proposal']),
                dict(sort=column))
            object_list = response.context['object_list']

            for index, sorted_date in enumerate(sorted_dates):
                self.assertEquals(sorted_date,
                                  getattr(object_list[index], column),
                                  'Testing date sort failed for' + column)
            self.assertEquals(
                None, getattr(object_list[len(object_list) - 2], column),
                'Testing date sort failed for' + column)
            self.assertEquals(
                None, getattr(object_list[len(object_list) - 1], column),
                'Testing date sort failed for' + column)

        # Test Last Modified
        response = self.client.get(
            reverse('publicweb_item_list',
                    args=[self.bettysorg.slug, 'proposal']),
            {'sort': 'last_modified'})
        object_list = response.context['object_list']
        for index, sorted_last_modified in enumerate(sorted_last_modifieds):
            # Replace Microsecond to enable good results on MySQL and SQLLite
            sorted_list_last_modified = sorted_last_modified.replace(
                microsecond=0)
            object_list_last_modified = getattr(
                object_list[index], 'last_modified').replace(microsecond=0)
            self.assertEquals(sorted_list_last_modified,
                              object_list_last_modified,
                              'Testing date sort failed for last_modified')

        # At this point, the ids in browser are all out of order, so good time to test id sort
        response = self.client.get(
            reverse('publicweb_item_list',
                    args=[self.bettysorg.slug, 'proposal']), {'sort': 'id'})
        object_list = response.context['object_list']
        for index, sorted_id in enumerate(sorted_ids):
            self.assertEquals(sorted_id, getattr(object_list[index], 'id'),
                              'Testing id sort failed')

        # Test Feedback
        response = self.client.get(
            reverse('publicweb_item_list',
                    args=[self.bettysorg.slug, 'proposal']),
            {'sort': 'feedback'})
        object_list = response.context['object_list']
        for index, sorted_feedbackcount in enumerate(sorted_feedbackcounts):
            self.assertEquals(sorted_feedbackcount,
                              object_list[index].feedbackcount(),
                              'Testing feedbackcount sort failed.')

        # Test Excerpt
        response = self.client.get(
            reverse('publicweb_item_list',
                    args=[self.bettysorg.slug, 'proposal']),
            {'sort': 'excerpt'})
        object_list = response.context['object_list']
        for index, sorted_excerpt in enumerate(sorted_excerpts):
            self.assertEquals(sorted_excerpt,
                              getattr(object_list[index], 'excerpt'),
                              'Testing excerpt sort failed')
Example #23
0
 def test_model_feedbackcount_changes(self):
     decision = self.make_decision()
     self.instance_attribute_has_value(decision, "feedbackcount", 0)
     feedback = Feedback(description="Feedback test data", decision=decision, author=self.user)
     feedback.save()
     self.instance_attribute_has_value(decision, "feedbackcount", 1)       
Example #24
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'])
Example #25
0
 def test_feedback_can_have_empty_description(self):
     decision = self.make_decision()
     feedback = Feedback(rating=Feedback.CONSENT_STATUS, decision=decision)
     self.instance_validates(feedback)
Example #26
0
 def test_feedback_has_author(self):
     decision = self.make_decision()
     feedback = Feedback(description="Feedback test data",
                         decision=decision)
     self.model_has_attribute(feedback, "author")
Example #27
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))