From ab929b07e1cf8dee95f5fb38f0adc67bcbac701f Mon Sep 17 00:00:00 2001 From: Scot Hacker Date: Sun, 7 Apr 2019 23:55:31 -0700 Subject: [PATCH] Limit attachments to specified file types --- README.md | 10 +++++++++- todo/templates/todo/task_detail.html | 4 ++-- todo/views/task_detail.py | 22 +++++++++++++++++----- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ed7275b..f1f9a54 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ assignment application for Django, designed to be dropped into an existing site * Mobile-friendly (work in progress) * Separate view for My Tasks (across lists) * Batch-import tasks via CSV +* Multiple file attachments per task (see settings) * Integrated mail tracking (unify a task list with an email box) @@ -39,6 +40,8 @@ Identical list names can exist in different groups, but not in the same group. Emails are generated to the assigned-to person when new tasks are created. +File attachments of a few types are allowed on tasks by default. See settings to disable or to limit filetypes. + Comment threads can be added to tasks. Each participant in a thread receives email when new comments are added. django-todo is auth-only. You must set up a login system and at least one group before deploying. @@ -101,7 +104,7 @@ Add links to your site's navigation system: My Tasks ``` -django-todo makes use of the Django `messages` system. Make sure you have something like [this](https://docs.djangoproject.com/en/2.0/ref/contrib/messages/#displaying-messages) (link) in your `base.html`. +django-todo makes use of the Django `messages` system. Make sure you have something like [this](https://docs.djangoproject.com/en/2.1/ref/contrib/messages/#displaying-messages) (link) in your `base.html`. Log in and access `/todo`! @@ -136,6 +139,11 @@ TODO_DEFAULT_LIST_SLUG = 'tickets' # Defaults to "/" TODO_PUBLIC_SUBMIT_REDIRECT = 'dashboard' +# Enable or disable file attachments on Tasks +# Optionally limit list of allowed filetypes +TODO_ALLOW_FILE_ATTACHMENTS = True +TODO_ALLOWED_FILE_ATTACHMENTS = [".jpg", ".gif", ".csv", ".pdf", ".zip"] + # additionnal classes the comment body should hold # adding "text-monospace" makes comment monospace TODO_COMMENT_CLASSES = [] diff --git a/todo/templates/todo/task_detail.html b/todo/templates/todo/task_detail.html index eea9c91..1a3fd84 100644 --- a/todo/templates/todo/task_detail.html +++ b/todo/templates/todo/task_detail.html @@ -124,7 +124,7 @@
{% if task.attachment_set.count %}
- +
@@ -147,7 +147,7 @@ {% endif %} - + {% csrf_token %}
diff --git a/todo/views/task_detail.py b/todo/views/task_detail.py index 4351130..2d10844 100644 --- a/todo/views/task_detail.py +++ b/todo/views/task_detail.py @@ -1,4 +1,5 @@ import datetime +import os import bleach from django import forms @@ -117,15 +118,26 @@ def task_detail(request, task_id: int) -> HttpResponse: # Handle uploaded files if request.FILES.get("attachment_file_input"): + file = request.FILES.get("attachment_file_input") + + # Validate inbound file extension against allowed filetypes + # FIXME: Move defaults to centralized module + allowed_extensions = ( + settings.TODO_ALLOWED_FILE_ATTACHMENTS + if hasattr(settings, "TODO_ALLOWED_FILE_ATTACHMENTS") + else [".jpg", ".gif", ".csv", ".pdf", ".zip"] + ) + name, extension = os.path.splitext(file.name) + if extension not in allowed_extensions: + messages.error(request, f"This site does not allow upload of {extension} files.") + return redirect("todo:task_detail", task_id=task.id) + Attachment.objects.create( - task=task, - added_by=request.user, - timestamp=datetime.datetime.now(), - file=request.FILES.get("attachment_file_input"), + task=task, added_by=request.user, timestamp=datetime.datetime.now(), file=file ) return redirect("todo:task_detail", task_id=task.id) - # For the context: Settings for file attachments defaults to True + # Settings for file attachments defaults to True # FIXME: Move settings defaults to a central location? attachments_enabled = True if (
File