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
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_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_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 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_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)
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_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_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")
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)
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
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)
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")
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
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 _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 _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))