Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connect users in tracked mail tasks #116

Merged
merged 5 commits into from
Mar 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,15 @@ TODO_MAIL_TRACKERS = {
}
```

Optionally, the email addresses of incoming emails can be mapped back to django users. If a user emails the test_tracker, and also is a registered User in your application, the user will show up as having created the task or comment. By default, only the email address will show up.

This isn't enabled by default, as some domains are misconfigured and do not prevent impersonation. If this option is enabled and your setup doesn't properly authenticate emails, malicious incoming emails might mistakenly be attributed to users.

Settings:
```python
TODO_MAIL_USER_MAPPER = None # Set to True if you would like to match users. If you do not have authentication setup, do not set this to True.
```

A mail worker can be started with:

```sh
Expand Down
2 changes: 2 additions & 0 deletions test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,5 @@
"django.request": {"handlers": ["console"], "level": "DEBUG", "propagate": True},
},
}

TODO_MAIL_USER_MAPPER = None
20 changes: 20 additions & 0 deletions todo/mail/consumers/tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
from email.charset import Charset as EMailCharset
from django.db import transaction
from django.db.models import Count
from django.contrib.auth import get_user_model
from django.conf import settings
from html2text import html2text
from email.utils import parseaddr
from todo.models import Comment, Task, TaskList

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -128,13 +131,15 @@ def insert_message(task_list, message, priority, task_title_format):
priority=priority,
title=format_task_title(task_title_format, message),
task_list=task_list,
created_by=match_user(message_from),
)
logger.info("using task: %r", best_task)

comment, comment_created = Comment.objects.get_or_create(
task=best_task,
email_message_id=message_id,
defaults={"email_from": message_from, "body": text},
author=match_user(message_from), # TODO: Write test for this
)
logger.info("created comment: %r", comment)

Expand All @@ -149,3 +154,18 @@ def tracker_consumer(
except Exception:
# ignore exceptions during insertion, in order to avoid
logger.exception("got exception while inserting message")


def match_user(email):
""" This function takes an email and checks for a registered user."""

if not settings.TODO_MAIL_USER_MAPPER:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice.

user = None
else:
try:
# Find the first user that matches the email
user = get_user_model().objects.get(email=parseaddr(email)[1])
except get_user_model().DoesNotExist:
user = None

return user
56 changes: 56 additions & 0 deletions todo/tests/test_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,59 @@ def test_tracker_task_creation(todo_setup, django_user_model):
Comment.objects.get(
task=task, body__contains="test3 content", email_message_id="<[email protected]>"
)

def test_tracker_email_match(todo_setup, django_user_model, settings):
"""
Ensure that a user is added to new lists when sent from registered email
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding a test!

"""
settings.TODO_MAIL_USER_MAPPER = True

u1 = django_user_model.objects.get(username="u1")

msg = make_message("test1 subject", "test1 content")
msg["From"] = u1.email
msg["Message-ID"] = "<[email protected]>"

# test task creation
task_count = Task.objects.count()
consumer([msg])

assert task_count + 1 == Task.objects.count(), "task wasn't created"
task = Task.objects.filter(title="[TEST] test1 subject").first()
assert task is not None, "task was created with the wrong name"
assert task.created_by == u1

# Check no match
msg = make_message("test2 subject", "test2 content")
msg["From"] = "[email protected]"
msg["Message-ID"] = "<[email protected]>"

# test task creation
task_count = Task.objects.count()
consumer([msg])

assert task_count + 1 == Task.objects.count(), "task wasn't created"
task = Task.objects.filter(title="[TEST] test2 subject").first()
assert task.created_by == None


def test_tracker_match_users_false(todo_setup, django_user_model, settings):
"""
Do not match users on incoming mail if TODO_MAIL_USER_MAPPER is False
"""
settings.TODO_MAIL_USER_MAPPER = None

u1 = django_user_model.objects.get(username="u1")

msg = make_message("test1 subject", "test1 content")
msg["From"] = u1.email
msg["Message-ID"] = "<[email protected]>"

# test task creation
task_count = Task.objects.count()
consumer([msg])

assert task_count + 1 == Task.objects.count(), "task wasn't created"
task = Task.objects.filter(title="[TEST] test1 subject").first()
assert task is not None, "task was created with the wrong name"
assert task.created_by == None