def test_ms_thread_id(): id = '<test/message@localhost>' now = timezone.now() index = services.make_ms_thread_index(id, now) parsed = parse_ms_thread_index(index) assert parsed[0] == hashlib.md5(id.encode('utf-8')).hexdigest() # always only one time assert (now - parsed[1][0]).seconds <= 2
def send_issue_notification(self, users): from taiga.projects.notifications.services import _make_template_mail, make_ms_thread_index domain = settings.SITES["api"]["domain"].split(":")[0] or settings.SITES["api"]["domain"] issues = Issue.objects.filter(status__is_closed=False) projects = Project.objects.filter(issues__in=issues, blocked_code__isnull=True).distinct() projects_with_issues = [] for project in projects: url = get_absolute_url('/project/{}/issue'.format(project.slug)) project_issues = issues.filter(project=project).distinct() nr_issues = project_issues.count() issue_types = [] nr_bugs = 0 for issue_type in project.issue_types.all(): nr = project_issues.filter(type=issue_type).count() if nr: if issue_type.name == 'Bug': nr_bugs = nr issue_types += [{'nr': nr, 'name': issue_type.name, 'color': issue_type.color}] projects_with_issues += [{'project': project, 'issues': project_issues, 'nr_bugs': nr_bugs, 'url': url, 'nr_issues': nr_issues, 'issue_types': issue_types}] projects_with_issues = sorted(projects_with_issues, key=lambda project: project['nr_bugs'], reverse=True) context = {'projects': projects_with_issues, 'summary': "".join([u"- {}: {} ".format(p['project'], p['nr_bugs']) for p in projects_with_issues])} email = _make_template_mail('issues/issues-list-monthly') msg_id = 'taiga-system' now = datetime.datetime.now() format_args = { "project_name": 'taiga-system', "project_slug": 'taiga-system', "msg_id": msg_id, "time": int(now.timestamp()), "domain": domain } headers = { "Message-ID": "<{project_slug}/{msg_id}/{time}@{domain}>".format(**format_args), "In-Reply-To": "<{project_slug}/{msg_id}@{domain}>".format(**format_args), "References": "<{project_slug}/{msg_id}@{domain}>".format(**format_args), "List-ID": 'Taiga/{project_name} <taiga.{project_slug}@{domain}>'.format(**format_args), "Thread-Index": make_ms_thread_index("<{project_slug}/{msg_id}@{domain}>".format(**format_args), now) } for user in users: context["user"] = user context["lang"] = user.lang or settings.LANGUAGE_CODE email.send(user.email, context, headers=headers)
def send_issue_notification(self, users): from taiga.projects.notifications.services import _make_template_mail, make_ms_thread_index domain = settings.SITES["api"]["domain"].split(":")[0] or settings.SITES["api"]["domain"] now = timezone.now() time_diff = now - datetime.timedelta(seconds=NOTIFY_ISSUES_TO_SU_INTERVAL) issues = Issue.objects.filter(modified_date__gte=time_diff, status__is_closed=False) projects = Project.objects.filter(issues__in=issues).distinct() projects_with_issues = [] for project in projects: url = get_absolute_url('/project/{}/issue'.format(project.slug)) project_issues = issues.filter(project=project).distinct() nr_issues = project_issues.count() projects_with_issues += [(project, project_issues, url, nr_issues)] projects_with_issues = sorted(projects_with_issues, key=lambda project: project[3], reverse=True) context = {'projects': projects_with_issues, 'summary': "".join([u"- {}: {} ".format(p[0], p[3]) for p in projects_with_issues])} email = _make_template_mail('issues/issues-list') msg_id = 'taiga-system' now = datetime.datetime.now() format_args = { "project_name": 'taiga-system', "project_slug": 'taiga-system', "msg_id": msg_id, "time": int(now.timestamp()), "domain": domain } headers = { "Message-ID": "<{project_slug}/{msg_id}/{time}@{domain}>".format(**format_args), "In-Reply-To": "<{project_slug}/{msg_id}@{domain}>".format(**format_args), "References": "<{project_slug}/{msg_id}@{domain}>".format(**format_args), "List-ID": 'Taiga/{project_name} <taiga.{project_slug}@{domain}>'.format(**format_args), "Thread-Index": make_ms_thread_index("<{project_slug}/{msg_id}@{domain}>".format(**format_args), now) } for user in users: context["user"] = user context["lang"] = user.lang or settings.LANGUAGE_CODE email.send(user.email, context, headers=headers)
def test_send_notifications_using_services_method_for_wiki_pages(settings, mail): settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL = 1 project = f.ProjectFactory.create() role = f.RoleFactory.create(project=project, permissions=['view_issues', 'view_us', 'view_tasks', 'view_wiki_pages']) member1 = f.MembershipFactory.create(project=project, role=role) member2 = f.MembershipFactory.create(project=project, role=role) wiki = f.WikiPageFactory.create(project=project, owner=member2.user) history_change = f.HistoryEntryFactory.create( project=project, user={"pk": member1.user.id}, comment="", type=HistoryType.change, key="wiki.wikipage:{}".format(wiki.id), is_hidden=False, diff=[] ) history_create = f.HistoryEntryFactory.create( project=project, user={"pk": member1.user.id}, comment="", type=HistoryType.create, key="wiki.wikipage:{}".format(wiki.id), is_hidden=False, diff=[] ) history_delete = f.HistoryEntryFactory.create( project=project, user={"pk": member1.user.id}, comment="test:delete", type=HistoryType.delete, key="wiki.wikipage:{}".format(wiki.id), is_hidden=False, diff=[] ) take_snapshot(wiki, user=wiki.owner) services.send_notifications(wiki, history=history_create) services.send_notifications(wiki, history=history_change) services.send_notifications(wiki, history=history_delete) assert models.HistoryChangeNotification.objects.count() == 3 assert len(mail.outbox) == 0 time.sleep(1) services.process_sync_notifications() assert len(mail.outbox) == 3 # test headers domain = settings.SITES["api"]["domain"].split(":")[0] or settings.SITES["api"]["domain"] for msg in mail.outbox: m_id = "{project_slug}/{msg_id}".format( project_slug=project.slug, msg_id=wiki.slug ) message_id = "<{m_id}/".format(m_id=m_id) message_id_domain = "@{domain}>".format(domain=domain) in_reply_to = "<{m_id}@{domain}>".format(m_id=m_id, domain=domain) list_id = "Taiga/{p_name} <taiga.{p_slug}@{domain}>" \ .format(p_name=project.name, p_slug=project.slug, domain=domain) assert msg.extra_headers headers = msg.extra_headers # can't test the time part because it's set when sending # check what we can assert 'Message-ID' in headers assert message_id in headers.get('Message-ID') assert message_id_domain in headers.get('Message-ID') assert 'In-Reply-To' in headers assert in_reply_to == headers.get('In-Reply-To') assert 'References' in headers assert in_reply_to == headers.get('References') assert 'List-ID' in headers assert list_id == headers.get('List-ID') assert 'Thread-Index' in headers # hashes should match for identical ids and times # we check the actual method in test_ms_thread_id() msg_time = headers.get('Message-ID').split('/')[2].split('@')[0] msg_ts = datetime.datetime.fromtimestamp(int(msg_time)) assert services.make_ms_thread_index(in_reply_to, msg_ts) == headers.get('Thread-Index')
def test_send_notifications_using_services_method_for_wiki_pages( settings, mail): settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL = 1 project = f.ProjectFactory.create() role = f.RoleFactory.create(project=project, permissions=[ 'view_issues', 'view_us', 'view_tasks', 'view_wiki_pages' ]) member1 = f.MembershipFactory.create(project=project, role=role) member2 = f.MembershipFactory.create(project=project, role=role) wiki = f.WikiPageFactory.create(project=project, owner=member2.user) history_change = f.HistoryEntryFactory.create( project=project, user={"pk": member1.user.id}, comment="test:change", type=HistoryType.change, key="wiki.wikipage:{}".format(wiki.id), is_hidden=False, diff=[]) history_create = f.HistoryEntryFactory.create( project=project, user={"pk": member1.user.id}, comment="", type=HistoryType.create, key="wiki.wikipage:{}".format(wiki.id), is_hidden=False, diff=[]) history_delete = f.HistoryEntryFactory.create( project=project, user={"pk": member1.user.id}, comment="test:delete", type=HistoryType.delete, key="wiki.wikipage:{}".format(wiki.id), is_hidden=False, diff=[]) take_snapshot(wiki, user=wiki.owner) services.send_notifications(wiki, history=history_create) services.send_notifications(wiki, history=history_change) services.send_notifications(wiki, history=history_delete) assert models.HistoryChangeNotification.objects.count() == 3 assert len(mail.outbox) == 0 time.sleep(1) services.process_sync_notifications() assert len(mail.outbox) == 3 # test headers domain = settings.SITES["api"]["domain"].split( ":")[0] or settings.SITES["api"]["domain"] for msg in mail.outbox: m_id = "{project_slug}/{msg_id}".format(project_slug=project.slug, msg_id=wiki.slug) message_id = "<{m_id}/".format(m_id=m_id) message_id_domain = "@{domain}>".format(domain=domain) in_reply_to = "<{m_id}@{domain}>".format(m_id=m_id, domain=domain) list_id = "Taiga/{p_name} <taiga.{p_slug}@{domain}>" \ .format(p_name=project.name, p_slug=project.slug, domain=domain) assert msg.extra_headers headers = msg.extra_headers # can't test the time part because it's set when sending # check what we can assert 'Message-ID' in headers assert message_id in headers.get('Message-ID') assert message_id_domain in headers.get('Message-ID') assert 'In-Reply-To' in headers assert in_reply_to == headers.get('In-Reply-To') assert 'References' in headers assert in_reply_to == headers.get('References') assert 'List-ID' in headers assert list_id == headers.get('List-ID') assert 'Thread-Index' in headers # hashes should match for identical ids and times # we check the actual method in test_ms_thread_id() msg_time = headers.get('Message-ID').split('/')[2].split('@')[0] msg_ts = datetime.datetime.fromtimestamp(int(msg_time)) assert services.make_ms_thread_index( in_reply_to, msg_ts) == headers.get('Thread-Index')
def test_send_notifications_using_services_method(settings, mail): settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL = 1 project = f.ProjectFactory.create() role = f.RoleFactory.create(project=project, permissions=[ 'view_issues', 'view_us', 'view_tasks', 'view_wiki_pages' ]) member1 = f.MembershipFactory.create(project=project, role=role) member2 = f.MembershipFactory.create(project=project, role=role) history_change = MagicMock() history_change.user = {"pk": member1.user.pk} history_change.comment = "" history_change.type = HistoryType.change history_change.is_hidden = False history_create = MagicMock() history_create.user = {"pk": member1.user.pk} history_create.comment = "" history_create.type = HistoryType.create history_create.is_hidden = False history_delete = MagicMock() history_delete.user = {"pk": member1.user.pk} history_delete.comment = "" history_delete.type = HistoryType.delete history_delete.is_hidden = False # Issues issue = f.IssueFactory.create(project=project, owner=member2.user) take_snapshot(issue, user=issue.owner) services.send_notifications(issue, history=history_create) services.send_notifications(issue, history=history_change) services.send_notifications(issue, history=history_delete) # Userstories us = f.UserStoryFactory.create(project=project, owner=member2.user) take_snapshot(us, user=us.owner) services.send_notifications(us, history=history_create) services.send_notifications(us, history=history_change) services.send_notifications(us, history=history_delete) # Tasks task = f.TaskFactory.create(project=project, owner=member2.user) take_snapshot(task, user=task.owner) services.send_notifications(task, history=history_create) services.send_notifications(task, history=history_change) services.send_notifications(task, history=history_delete) # Wiki pages wiki = f.WikiPageFactory.create(project=project, owner=member2.user) take_snapshot(wiki, user=wiki.owner) services.send_notifications(wiki, history=history_create) services.send_notifications(wiki, history=history_change) services.send_notifications(wiki, history=history_delete) assert models.HistoryChangeNotification.objects.count() == 12 assert len(mail.outbox) == 0 time.sleep(1) services.process_sync_notifications() assert len(mail.outbox) == 12 # test headers events = [issue, us, task, wiki] domain = settings.SITES["api"]["domain"].split( ":")[0] or settings.SITES["api"]["domain"] i = 0 for msg in mail.outbox: # each event has 3 msgs event = events[math.floor(i / 3)] # each set of 3 should have the same headers if i % 3 == 0: if hasattr(event, 'ref'): e_slug = event.ref elif hasattr(event, 'slug'): e_slug = event.slug else: e_slug = 'taiga-system' m_id = "{project_slug}/{msg_id}".format(project_slug=project.slug, msg_id=e_slug) message_id = "<{m_id}/".format(m_id=m_id) message_id_domain = "@{domain}>".format(domain=domain) in_reply_to = "<{m_id}@{domain}>".format(m_id=m_id, domain=domain) list_id = "Taiga/{p_name} <taiga.{p_slug}@{domain}>" \ .format(p_name=project.name, p_slug=project.slug, domain=domain) assert msg.extra_headers headers = msg.extra_headers # can't test the time part because it's set when sending # check what we can assert 'Message-ID' in headers assert message_id in headers.get('Message-ID') assert message_id_domain in headers.get('Message-ID') assert 'In-Reply-To' in headers assert in_reply_to == headers.get('In-Reply-To') assert 'References' in headers assert in_reply_to == headers.get('References') assert 'List-ID' in headers assert list_id == headers.get('List-ID') assert 'Thread-Index' in headers # always is b64 encoded 22 bytes assert len(base64.b64decode(headers.get('Thread-Index'))) == 22 # hashes should match for identical ids and times # we check the actual method in test_ms_thread_id() msg_time = headers.get('Message-ID').split('/')[2].split('@')[0] msg_ts = datetime.datetime.fromtimestamp(int(msg_time)) assert services.make_ms_thread_index( in_reply_to, msg_ts) == headers.get('Thread-Index') i += 1
def test_send_notifications_using_services_method(settings, mail): settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL = 1 project = f.ProjectFactory.create() role = f.RoleFactory.create(project=project, permissions=['view_issues', 'view_us', 'view_tasks', 'view_wiki_pages']) member1 = f.MembershipFactory.create(project=project, role=role) member2 = f.MembershipFactory.create(project=project, role=role) history_change = MagicMock() history_change.user = {"pk": member1.user.pk} history_change.comment = "" history_change.type = HistoryType.change history_change.is_hidden = False history_create = MagicMock() history_create.user = {"pk": member1.user.pk} history_create.comment = "" history_create.type = HistoryType.create history_create.is_hidden = False history_delete = MagicMock() history_delete.user = {"pk": member1.user.pk} history_delete.comment = "" history_delete.type = HistoryType.delete history_delete.is_hidden = False # Issues issue = f.IssueFactory.create(project=project, owner=member2.user) take_snapshot(issue, user=issue.owner) services.send_notifications(issue, history=history_create) services.send_notifications(issue, history=history_change) services.send_notifications(issue, history=history_delete) # Userstories us = f.UserStoryFactory.create(project=project, owner=member2.user) take_snapshot(us, user=us.owner) services.send_notifications(us, history=history_create) services.send_notifications(us, history=history_change) services.send_notifications(us, history=history_delete) # Tasks task = f.TaskFactory.create(project=project, owner=member2.user) take_snapshot(task, user=task.owner) services.send_notifications(task, history=history_create) services.send_notifications(task, history=history_change) services.send_notifications(task, history=history_delete) # Wiki pages wiki = f.WikiPageFactory.create(project=project, owner=member2.user) take_snapshot(wiki, user=wiki.owner) services.send_notifications(wiki, history=history_create) services.send_notifications(wiki, history=history_change) services.send_notifications(wiki, history=history_delete) assert models.HistoryChangeNotification.objects.count() == 12 assert len(mail.outbox) == 0 time.sleep(1) services.process_sync_notifications() assert len(mail.outbox) == 12 # test headers events = [issue, us, task, wiki] domain = settings.SITES["api"]["domain"].split(":")[0] or settings.SITES["api"]["domain"] i = 0 for msg in mail.outbox: # each event has 3 msgs event = events[math.floor(i / 3)] # each set of 3 should have the same headers if i % 3 == 0: if hasattr(event, 'ref'): e_slug = event.ref elif hasattr(event, 'slug'): e_slug = event.slug else: e_slug = 'taiga-system' m_id = "{project_slug}/{msg_id}".format( project_slug=project.slug, msg_id=e_slug ) message_id = "<{m_id}/".format(m_id=m_id) message_id_domain = "@{domain}>".format(domain=domain) in_reply_to = "<{m_id}@{domain}>".format(m_id=m_id, domain=domain) list_id = "Taiga/{p_name} <taiga.{p_slug}@{domain}>" \ .format(p_name=project.name, p_slug=project.slug, domain=domain) assert msg.extra_headers headers = msg.extra_headers # can't test the time part because it's set when sending # check what we can assert 'Message-ID' in headers assert message_id in headers.get('Message-ID') assert message_id_domain in headers.get('Message-ID') assert 'In-Reply-To' in headers assert in_reply_to == headers.get('In-Reply-To') assert 'References' in headers assert in_reply_to == headers.get('References') assert 'List-ID' in headers assert list_id == headers.get('List-ID') assert 'Thread-Index' in headers # always is b64 encoded 22 bytes assert len(base64.b64decode(headers.get('Thread-Index'))) == 22 # hashes should match for identical ids and times # we check the actual method in test_ms_thread_id() msg_time = headers.get('Message-ID').split('/')[2].split('@')[0] msg_ts = datetime.datetime.fromtimestamp(int(msg_time)) assert services.make_ms_thread_index(in_reply_to, msg_ts) == headers.get('Thread-Index') i += 1
def test_send_notifications_using_services_method_for_issues(settings, mail): settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL = 1 project = f.ProjectFactory.create() role = f.RoleFactory.create( project=project, permissions=["view_issues", "view_us", "view_tasks", "view_wiki_pages"] ) member1 = f.MembershipFactory.create(project=project, role=role) member2 = f.MembershipFactory.create(project=project, role=role) issue = f.IssueFactory.create(project=project, owner=member2.user) history_change = f.HistoryEntryFactory.create( user={"pk": member1.user.id}, comment="", type=HistoryType.change, key="issues.issue:{}".format(issue.id), is_hidden=False, diff=[], ) history_create = f.HistoryEntryFactory.create( user={"pk": member1.user.id}, comment="", type=HistoryType.create, key="issues.issue:{}".format(issue.id), is_hidden=False, diff=[], ) history_delete = f.HistoryEntryFactory.create( user={"pk": member1.user.id}, comment="test:delete", type=HistoryType.delete, key="issues.issue:{}".format(issue.id), is_hidden=False, diff=[], ) take_snapshot(issue, user=issue.owner) services.send_notifications(issue, history=history_create) services.send_notifications(issue, history=history_change) services.send_notifications(issue, history=history_delete) assert models.HistoryChangeNotification.objects.count() == 3 assert len(mail.outbox) == 0 time.sleep(1) services.process_sync_notifications() assert len(mail.outbox) == 3 # test headers domain = settings.SITES["api"]["domain"].split(":")[0] or settings.SITES["api"]["domain"] for msg in mail.outbox: m_id = "{project_slug}/{msg_id}".format(project_slug=project.slug, msg_id=issue.ref) message_id = "<{m_id}/".format(m_id=m_id) message_id_domain = "@{domain}>".format(domain=domain) in_reply_to = "<{m_id}@{domain}>".format(m_id=m_id, domain=domain) list_id = "Taiga/{p_name} <taiga.{p_slug}@{domain}>".format( p_name=project.name, p_slug=project.slug, domain=domain ) assert msg.extra_headers headers = msg.extra_headers # can't test the time part because it's set when sending # check what we can assert "Message-ID" in headers assert message_id in headers.get("Message-ID") assert message_id_domain in headers.get("Message-ID") assert "In-Reply-To" in headers assert in_reply_to == headers.get("In-Reply-To") assert "References" in headers assert in_reply_to == headers.get("References") assert "List-ID" in headers assert list_id == headers.get("List-ID") assert "Thread-Index" in headers # always is b64 encoded 22 bytes assert len(base64.b64decode(headers.get("Thread-Index"))) == 22 # hashes should match for identical ids and times # we check the actual method in test_ms_thread_id() msg_time = headers.get("Message-ID").split("/")[2].split("@")[0] msg_ts = datetime.datetime.fromtimestamp(int(msg_time)) assert services.make_ms_thread_index(in_reply_to, msg_ts) == headers.get("Thread-Index")