def setUp(self): self.user = User.objects.create_user('testuser', '*****@*****.**', 'testPass') self.client.login(username='******', password='******') # Create test data MailingList.objects.create(name="*****@*****.**", subject_prefix="[example] ") # Create 3 threads messages = [] for msgnum in range(3): msg = EmailMessage() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<id%d>" % (msgnum + 1) msg["Subject"] = "Dummy message %d" % (msgnum + 1) msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg) messages.append(msg) # 1st is unread, 2nd is read, 3rd is updated thread_2 = Thread.objects.get(thread_id=get_message_id_hash("<id2>")) thread_3 = Thread.objects.get(thread_id=get_message_id_hash("<id3>")) LastView.objects.create(user=self.user, thread=thread_2) LastView.objects.create(user=self.user, thread=thread_3) msg4 = EmailMessage() msg4["From"] = "*****@*****.**" msg4["Message-ID"] = "<id4>" msg4["Subject"] = "Dummy message 4" msg4["In-Reply-To"] = "<id3>" msg4.set_payload("Dummy message") add_to_list("*****@*****.**", msg4)
def setUp(self): self.user = User.objects.create_user( 'testuser', '*****@*****.**', 'testPass') self.client.login(username='******', password='******') # Create test data MailingList.objects.create( name="*****@*****.**", subject_prefix="[example] ") # Create 3 threads messages = [] for msgnum in range(3): msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<id%d>" % (msgnum+1) msg["Subject"] = "Dummy message %d" % (msgnum+1) msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg) messages.append(msg) # 1st is unread, 2nd is read, 3rd is updated thread_2 = Thread.objects.get(thread_id=get_message_id_hash("<id2>")) thread_3 = Thread.objects.get(thread_id=get_message_id_hash("<id3>")) LastView.objects.create(user=self.user, thread=thread_2) LastView.objects.create(user=self.user, thread=thread_3) msg4 = Message() msg4["From"] = "*****@*****.**" msg4["Message-ID"] = "<id4>" msg4["Subject"] = "Dummy message 4" msg4["In-Reply-To"] = "<id3>" msg4.set_payload("Dummy message") add_to_list("*****@*****.**", msg4)
def test_profile(self): response = self.client.get(reverse('hk_user_last_views')) self.assertContains(response, "<td>[email protected]</td>", count=2, status_code=200, html=True) self.assertContains(response, '<a href="{}">Dummy message 2</a>'.format( reverse("hk_thread", args=("*****@*****.**", get_message_id_hash("id2")))), count=2, status_code=200, html=True) self.assertContains(response, '<a href="{}">Dummy message 3</a>'.format( reverse("hk_thread", args=("*****@*****.**", get_message_id_hash("id3")))), count=2, status_code=200, html=True)
def _get_url(mlist_fqdn, msg_id=None): # We can't use HttpRequest.build_absolute_uri() because the mailman API may # be accessed via localhost. # https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.build_absolute_uri # https://docs.djangoproject.com/en/dev/ref/contrib/sites/#getting-the-current-domain-for-full-urls # result = urljoin(public_url, urlunquote( # reverse('hk_list_overview', args=[mlist_fqdn]))) # We use the MailDomain association from django_mailman3 to find out the # proper domain. if msg_id is None: url = reverse('hk_list_overview', args=[mlist_fqdn]) else: msg_hash = get_message_id_hash(msg_id.strip().strip("<>")) url = reverse('hk_message_index', kwargs={ "mlist_fqdn": mlist_fqdn, "message_id_hash": msg_hash }) relative_url = urlunquote(url) mail_domain = mlist_fqdn.split("@")[1] try: domain = MailDomain.objects.get(mail_domain=mail_domain).site.domain except MailDomain.DoesNotExist: domain = mail_domain return urljoin("https://%s" % domain, relative_url)
def test_reply_different_sender(self): self.user.first_name = "Django" self.user.last_name = "User" self.user.save() mm_user = Mock() self.mailman_client.get_user.side_effect = lambda name: mm_user mm_user.user_id = uuid.uuid1().int mm_user.addresses = ["*****@*****.**", "*****@*****.**"] mm_user.subscriptions = [] mlist = MailingList.objects.get(name="*****@*****.**") url = reverse('hk_message_reply', args=("*****@*****.**", get_message_id_hash("msg"))) with patch("hyperkitty.views.message.post_to_list") as posting_fn: response = self.client.post(url, { "message": "dummy reply content", "sender": "*****@*****.**", }) self.assertEqual(response.status_code, 200) self.assertEqual(posting_fn.call_count, 1) self.assertEqual(posting_fn.call_args[0][1:], (mlist, 'Re: Dummy Subject', 'dummy reply content', {'From': '*****@*****.**', 'In-Reply-To': '<msg>', 'References': '<msg>'})) result = json.loads(response.content) #print(result["message_html"]) self.assertIn("Django User", result["message_html"]) self.assertIn("dummy reply content", result["message_html"]) self.assertIn( get_gravatar_url("*****@*****.**", 120).replace("&", "&"), result["message_html"])
def test_display_fixed(self): msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Subject"] = "Dummy Subject" msg["Date"] = "Mon, 02 Feb 2015 13:00:00 +0300" msg["Message-ID"] = "<msg2>" msg.set_payload("Dummy message with @@ signs (looks like a patch)") add_to_list("*****@*****.**", msg) url1 = reverse('hk_message_index', args=("*****@*****.**", get_message_id_hash("msg"))) response1 = self.client.get(url1) self.assertNotContains(response1, "email-body fixed", status_code=200) url2 = reverse('hk_message_index', args=("*****@*****.**", get_message_id_hash("msg2"))) response2 = self.client.get(url2) self.assertContains(response2, "email-body fixed", status_code=200)
def check_neighbors(thread, expected_prev, expected_next): thread_id = get_message_id_hash("<id%s_1>" % thread) thread = Thread.objects.get(thread_id=thread_id) prev_th = next_th = None # convert to something I can compare if thread.prev_thread: prev_th = thread.prev_thread.thread_id if thread.next_thread: next_th = thread.next_thread.thread_id expected_prev = expected_prev and \ get_message_id_hash("<id%s_1>" % expected_prev) expected_next = expected_next and \ get_message_id_hash("<id%s_1>" % expected_next) # compare self.assertEqual(prev_th, expected_prev) self.assertEqual(next_th, expected_next)
def test_reply(self): self.user.first_name = "Django" self.user.last_name = "User" self.user.save() url = reverse('hk_message_reply', args=("*****@*****.**", get_message_id_hash("msg"))) with patch("hyperkitty.lib.posting.mailman.subscribe") as sub_fn: response = self.client.post(url, {"message": "dummy reply content"}) self.assertEqual(response.status_code, 200) self.assertTrue(sub_fn.called) result = json.loads(response.content) #print(result["message_html"]) self.assertIn("Django User", result["message_html"]) self.assertIn("dummy reply content", result["message_html"]) self.assertIn( get_gravatar_url("*****@*****.**", 120).replace("&", "&"), result["message_html"]) self.assertEqual(len(mail.outbox), 1) #print(mail.outbox[0].message()) self.assertEqual(mail.outbox[0].recipients(), ["*****@*****.**"]) self.assertEqual(mail.outbox[0].from_email, '"Django User" <*****@*****.**>') self.assertEqual(mail.outbox[0].subject, 'Re: Dummy Subject') self.assertEqual(mail.outbox[0].body, "dummy reply content") self.assertEqual(mail.outbox[0].message().get("references"), "<msg>") self.assertEqual(mail.outbox[0].message().get("in-reply-to"), "<msg>")
def test_vote_down(self): url = reverse('hk_message_vote', args=("*****@*****.**", get_message_id_hash("msg"))) resp = self.client.post(url, {"vote": "-1"}) self.assertEqual(resp.status_code, 200) result = json.loads(resp.content) self.assertEqual(result["like"], 0) self.assertEqual(result["dislike"], 1)
def test_thread(self): responses = [] for msgnum in range(3): threadid = get_message_id_hash("<id%d>" % (msgnum + 1)) response = self.client.get(reverse("hk_thread", args=("*****@*****.**", threadid))) responses.append(response) # There's always one icon in the right column, so all counts are +1 self.assertContains(responses[0], "fa-envelope", count=2, status_code=200) self.assertContains(responses[1], "fa-envelope", count=1, status_code=200) self.assertContains(responses[2], "fa-envelope", count=2, status_code=200)
def test_thread(self): responses = [] for msgnum in range(3): threadid = get_message_id_hash("<id%d>" % (msgnum+1)) response = self.client.get(reverse('hk_thread', args=( "*****@*****.**", threadid))) responses.append(response) # There's always one icon in the right column, so all counts are +1 self.assertContains(responses[0], "fa-envelope", count=2, status_code=200) self.assertContains(responses[1], "fa-envelope", count=1, status_code=200) self.assertContains(responses[2], "fa-envelope", count=2, status_code=200)
def test_email_escaped_body(self): msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Subject"] = "Dummy Subject" msg["Date"] = "Mon, 02 Feb 2015 13:00:00 +0300" msg["Message-ID"] = "<msg2>" msg.set_payload("Email address: [email protected]") add_to_list("*****@*****.**", msg) url = reverse('hk_message_index', args=("*****@*****.**", get_message_id_hash("msg2"))) response = self.client.get(url) self.assertNotContains(response, "*****@*****.**", status_code=200)
def test_email_escaped_sender(self): msg = Message() msg["From"] = "*****@*****.**" msg["Subject"] = "Dummy Subject" msg["Date"] = "Mon, 02 Feb 2015 13:00:00 +0300" msg["Message-ID"] = "<msg2>" msg.set_payload("Dummy content") add_to_list("*****@*****.**", msg) url = reverse('hk_message_index', args=("*****@*****.**", get_message_id_hash("msg2"))) response = self.client.get(url) self.assertNotContains(response, "*****@*****.**", status_code=200)
def test_reply_newthread(self): mlist = MailingList.objects.get(name="*****@*****.**") url = reverse('hk_message_reply', args=("*****@*****.**", get_message_id_hash("msg"))) with patch("hyperkitty.views.message.post_to_list") as posting_fn: response = self.client.post(url, {"message": "dummy reply content", "newthread": 1, "subject": "new subject"}) self.assertEqual(response.status_code, 200) self.assertEqual(posting_fn.call_count, 1) self.assertEqual(posting_fn.call_args[0][1:], (mlist, 'new subject', 'dummy reply content', {})) result = json.loads(response.content) self.assertEqual(result["message_html"], None)
def _get_url(mlist_fqdn, msg_id=None): # I don't think we can use HttpRequest.build_absolute_uri() because the # mailman API may be accessed via localhost # https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.build_absolute_uri # https://docs.djangoproject.com/en/dev/ref/contrib/sites/#getting-the-current-domain-for-full-urls #result = urljoin(public_url, urlunquote( # reverse('hk_list_overview', args=[mlist_fqdn]))) # So we return the relative URL and let the admin configure the public URL in Mailman if msg_id is None: url = reverse('hk_list_overview', args=[mlist_fqdn]) else: msg_hash = get_message_id_hash(msg_id.strip().strip("<>")) url = reverse('hk_message_index', kwargs={ "mlist_fqdn": mlist_fqdn, "message_id_hash": msg_hash}) return urlunquote(url)
def test_email_in_link_in_body(self): msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Subject"] = "Dummy Subject" msg["Date"] = "Mon, 02 Feb 2015 13:00:00 +0300" msg["Message-ID"] = "<msg2>" link = "http://example.com/list/[email protected]/message" msg.set_payload("Email address in link: %s" % link) add_to_list("*****@*****.**", msg) url = reverse('hk_message_index', args=("*****@*****.**", get_message_id_hash("msg2"))) response = self.client.get(url) self.assertContains( response, '<a href="{0}" rel="nofollow">{0}</a>'.format(link), status_code=200)
def test_reply_newthread(self): mlist = MailingList.objects.get(name="*****@*****.**") url = reverse('hk_message_reply', args=("*****@*****.**", get_message_id_hash("msg"))) with patch("hyperkitty.views.message.post_to_list") as posting_fn: response = self.client.post( url, { "message": "dummy reply content", "newthread": 1, "subject": "new subject" }) self.assertEqual(response.status_code, 200) self.assertEqual(posting_fn.call_count, 1) self.assertEqual(posting_fn.call_args[0][1:], (mlist, 'new subject', 'dummy reply content', {})) result = json.loads(response.content) self.assertEqual(result["message_html"], None)
def test_message_page(self): url = reverse('hk_message_index', args=("*****@*****.**", get_message_id_hash("msg"))) with self.settings(USE_L10N=False, DATETIME_FORMAT='Y-m-d H:i:s', TIME_FORMAT="H:i:s"): with timezone.override(timezone.utc): response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "Dummy message") self.assertContains(response, "Dummy Sender", count=1) self.assertContains(response, "Dummy Subject", count=3) self.assertNotContains(response, "*****@*****.**") self.assertContains(response, get_gravatar_url("*****@*****.**", 120).replace("&", "&")) self.assertContains(response, "*****@*****.**") self.assertContains(response, url) sender_time = '<span title="Sender\'s time: 2015-02-02 13:00:00">10:00:00</span>' self.assertIn(sender_time, response.content.decode("utf-8"))
def test_new_email_new_thread(self): msg = self._make_message() add_to_list("example-list", msg) self.assertEqual(len(self.events), 2) # The new_thread signal is received before the new_email signal, # because it is emitted by a listener of the new_email signal, but it # does not really matter. # # new_thread self.assertTrue("thread" in self.events[0][1]) thread = self.events[0][1]["thread"] self.assertTrue(isinstance(thread, Thread)) self.assertEqual(thread.thread_id, get_message_id_hash("dummy")) self.assertEqual(thread.emails.count(), 1) # # new_email self.assertTrue("email" in self.events[1][1]) email = self.events[1][1]["email"] self.assertTrue(isinstance(email, Email)) self.assertEqual(email.message_id, "dummy")
def test_new_email_new_thread(self): msg = self._make_message() add_to_list("example-list", msg) #print(repr(self.events)) self.assertEqual(len(self.events), 2) # The new_thread signal is received before the new_email signal, # because it is emitted by a listener of the new_email signal, but it # does not really matter. ## new_thread self.assertTrue("thread" in self.events[0][1]) thread = self.events[0][1]["thread"] self.assertTrue(isinstance(thread, Thread)) self.assertEqual(thread.thread_id, get_message_id_hash("dummy")) self.assertEqual(thread.emails.count(), 1) ## new_email self.assertTrue("email" in self.events[1][1]) email = self.events[1][1]["email"] self.assertTrue(isinstance(email, Email)) self.assertEqual(email.message_id, "dummy")
def test_reply_newthread(self): url = reverse('hk_message_reply', args=("*****@*****.**", get_message_id_hash("msg"))) with patch("hyperkitty.lib.posting.mailman.subscribe") as sub_fn: response = self.client.post(url, {"message": "dummy reply content", "newthread": 1, "subject": "new subject"}) self.assertEqual(response.status_code, 200) self.assertTrue(sub_fn.called) result = json.loads(response.content) self.assertEqual(result["message_html"], None) self.assertEqual(len(mail.outbox), 1) #print(mail.outbox[0].message()) self.assertEqual(mail.outbox[0].recipients(), ["*****@*****.**"]) self.assertEqual(mail.outbox[0].from_email, '*****@*****.**') self.assertEqual(mail.outbox[0].subject, 'new subject') self.assertEqual(mail.outbox[0].body, "dummy reply content") self.assertNotIn("references", mail.outbox[0].message()) self.assertNotIn("in-reply-to", mail.outbox[0].message())
def test_message_page(self): url = reverse('hk_message_index', args=("*****@*****.**", get_message_id_hash("msg"))) with self.settings(USE_L10N=False, DATETIME_FORMAT='Y-m-d H:i:s', TIME_FORMAT="H:i:s"): with timezone.override(timezone.utc): response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "Dummy message") self.assertContains(response, "Dummy Sender", count=1) self.assertContains(response, "Dummy Subject", count=3) self.assertNotContains(response, "*****@*****.**") self.assertContains( response, get_gravatar_url("*****@*****.**", 120).replace("&", "&")) self.assertContains(response, "*****@*****.**") self.assertContains(response, url) sender_time = '<span title="Sender\'s time: 2015-02-02 13:00:00">10:00:00</span>' self.assertIn(sender_time, response.content.decode("utf-8"))
def test_existing_thread(self): msg = EmailMessage() msg["From"] = "*****@*****.**" msg["Subject"] = "Fake Subject" msg["Message-ID"] = "<dummy>" msg["Date"] = "Fri, 02 Nov 2012 16:07:54" msg.set_payload("Fake Message") # Create a thread with the same message_id mlist = MailingList.objects.create(name="example-list") thread = Thread.objects.create(mailinglist=mlist, thread_id=get_message_id_hash("dummy")) # Add the message m_hash = add_to_list("example-list", msg) self.assertEqual(m_hash, thread.thread_id) self.assertEqual(thread.emails.count(), 1) # Get the email try: email = Email.objects.get(message_id="dummy") except Email.DoesNotExist: self.fail("No email found by id") self.assertEqual(email.thread, thread)
def test_reply(self): self.user.first_name = "Django" self.user.last_name = "User" self.user.save() mlist = MailingList.objects.get(name="*****@*****.**") url = reverse('hk_message_reply', args=("*****@*****.**", get_message_id_hash("msg"))) with patch("hyperkitty.views.message.post_to_list") as posting_fn: response = self.client.post(url, {"message": "dummy reply content"}) self.assertEqual(response.status_code, 200) self.assertEqual(posting_fn.call_count, 1) self.assertEqual(posting_fn.call_args[0][1:], (mlist, 'Re: Dummy Subject', 'dummy reply content', {'References': '<msg>', 'In-Reply-To': '<msg>'})) result = json.loads(response.content) #print(result["message_html"]) self.assertIn("Django User", result["message_html"]) self.assertIn("dummy reply content", result["message_html"]) self.assertIn( get_gravatar_url("*****@*****.**", 120).replace("&", "&"), result["message_html"])
def test_reply_different_sender(self): self.user.first_name = "Django" self.user.last_name = "User" self.user.save() EmailAddress.objects.create(user=self.user, verified=True, email="*****@*****.**") EmailAddress.objects.create(user=self.user, verified=True, email="*****@*****.**") mm_user = Mock() self.mailman_client.get_user.side_effect = lambda name: mm_user mm_user.user_id = uuid.uuid1().int mm_user.subscriptions = [] mlist = MailingList.objects.get(name="*****@*****.**") url = reverse('hk_message_reply', args=("*****@*****.**", get_message_id_hash("msg"))) with patch("hyperkitty.views.message.post_to_list") as posting_fn: response = self.client.post( url, { "message": "dummy reply content", "sender": "*****@*****.**", }) self.assertEqual(response.status_code, 200) self.assertEqual(posting_fn.call_count, 1) self.assertEqual( posting_fn.call_args[0][1:], (mlist, 'Re: Dummy Subject', 'dummy reply content', { 'From': '*****@*****.**', 'In-Reply-To': '<msg>', 'References': '<msg>' })) result = json.loads(response.content) self.assertIn("Django User", result["message_html"]) self.assertIn("dummy reply content", result["message_html"]) self.assertIn( get_gravatar_url("*****@*****.**", 120).replace("&", "&"), result["message_html"])
def test_reply_newthread(self): url = reverse('hk_message_reply', args=("*****@*****.**", get_message_id_hash("msg"))) with patch("hyperkitty.lib.posting.mailman.subscribe") as sub_fn: response = self.client.post( url, { "message": "dummy reply content", "newthread": 1, "subject": "new subject" }) self.assertEqual(response.status_code, 200) self.assertTrue(sub_fn.called) result = json.loads(response.content) self.assertEqual(result["message_html"], None) self.assertEqual(len(mail.outbox), 1) #print(mail.outbox[0].message()) self.assertEqual(mail.outbox[0].recipients(), ["*****@*****.**"]) self.assertEqual(mail.outbox[0].from_email, '*****@*****.**') self.assertEqual(mail.outbox[0].subject, 'new subject') self.assertEqual(mail.outbox[0].body, "dummy reply content") self.assertNotIn("references", mail.outbox[0].message()) self.assertNotIn("in-reply-to", mail.outbox[0].message())
def test_reply(self): self.user.first_name = "Django" self.user.last_name = "User" self.user.save() mlist = MailingList.objects.get(name="*****@*****.**") url = reverse('hk_message_reply', args=("*****@*****.**", get_message_id_hash("msg"))) with patch("hyperkitty.views.message.post_to_list") as posting_fn: response = self.client.post(url, {"message": "dummy reply content"}) self.assertEqual(response.status_code, 200) self.assertEqual(posting_fn.call_count, 1) self.assertEqual( posting_fn.call_args[0][1:], (mlist, 'Re: Dummy Subject', 'dummy reply content', { 'References': '<msg>', 'In-Reply-To': '<msg>' })) result = json.loads(response.content) self.assertIn("Django User", result["message_html"]) self.assertIn("dummy reply content", result["message_html"]) self.assertIn( get_gravatar_url("*****@*****.**", 120).replace("&", "&"), result["message_html"])
def test_delete_forbidden(self): url = reverse('hk_message_delete', args=("*****@*****.**", get_message_id_hash("msg"))) response = self.client.post(url) self.assertEqual(response.status_code, 403)
def test_unauth_vote(self): self.client.logout() url = reverse('hk_message_vote', args=("*****@*****.**", get_message_id_hash("msg"))) resp = self.client.post(url, {"vote": "1"}) self.assertEqual(resp.status_code, 403)
def _set_message_id_hash(self): from hyperkitty.lib.utils import get_message_id_hash # circular import if not self.message_id_hash: self.message_id_hash = get_message_id_hash(self.message_id)
def test_get_message_id_hash(self): msg_id = '<*****@*****.**>' expected = 'JJIGKPKB6CVDX6B2CUG4IHAJRIQIOUTP' self.assertEqual(utils.get_message_id_hash(msg_id), expected)
def Email_set_message_id_hash(sender, **kwargs): from hyperkitty.lib.utils import get_message_id_hash # circular import email = kwargs["instance"] if not email.message_id_hash: email.message_id_hash = get_message_id_hash(email.message_id)