Skip to content

Commit

Permalink
Connect users in tracked mail tasks (#116)
Browse files Browse the repository at this point in the history
* repair failing test, logging error in tracker.py

* match created_by users on tracked email reciept

* fix test and minor update

* updates to mail trackingr and user connection
  • Loading branch information
fross123 authored Mar 5, 2022
1 parent 79a272d commit 103b00a
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 0 deletions.
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:
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
"""
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

0 comments on commit 103b00a

Please sign in to comment.