diff --git a/README.md b/README.md
index 65ede23..5c15123 100644
--- a/README.md
+++ b/README.md
@@ -168,6 +168,8 @@ The previous `tox` system was removed with the v2 release, since we no longer ai
# Version History
+**2.2.1** Convert task delete and toggle_done views to POST only
+
**2.2.0** Re-instate enforcement of TODO_STAFF_ONLY setting
**2.1.1** Correct Python version requirement in documentation to Python 3.6
diff --git a/todo/__init__.py b/todo/__init__.py
index 33eaf46..cfae594 100644
--- a/todo/__init__.py
+++ b/todo/__init__.py
@@ -1,7 +1,7 @@
"""
A multi-user, multi-group task management and assignment system for Django.
"""
-__version__ = '2.2.0'
+__version__ = '2.2.1'
__author__ = 'Scot Hacker'
__email__ = 'shacker@birdhouse.org'
diff --git a/todo/templates/todo/list_detail.html b/todo/templates/todo/list_detail.html
index 3edc7ad..c699d1c 100644
--- a/todo/templates/todo/list_detail.html
+++ b/todo/templates/todo/list_detail.html
@@ -52,14 +52,17 @@
{% if task.assigned_to %}{{ task.assigned_to }}{% else %}Anyone{% endif %}
-
+
- |
+
+
+
{% endfor %}
diff --git a/todo/templates/todo/task_detail.html b/todo/templates/todo/task_detail.html
index 067d7ae..eddb130 100644
--- a/todo/templates/todo/task_detail.html
+++ b/todo/templates/todo/task_detail.html
@@ -12,21 +12,40 @@
-
- -
-
-
-
Assigned to:
{% if task.assigned_to %} {{ task.assigned_to.get_full_name }} {% else %} Anyone {% endif %}
@@ -37,7 +56,7 @@
-
Due date: {{ task.due_date }}
-
+
{% if task.completed %}
-
Completed on: {{ task.completed_date}}
@@ -47,7 +66,7 @@
Completed: {{ task.completed|yesno:"Yes,No" }}
{% endif %}
-
+
-
In list:
diff --git a/todo/tests/test_views.py b/todo/tests/test_views.py
index 72f2052..6c7188f 100644
--- a/todo/tests/test_views.py
+++ b/todo/tests/test_views.py
@@ -1,5 +1,4 @@
import bleach
-import json
import pytest
from django.contrib.auth import get_user_model
@@ -14,8 +13,6 @@ Next permissions tests - some views should respond for staffers only.
After that, view contents and behaviors.
"""
-# ### SMOKETESTS ###
-
@pytest.mark.django_db
def test_todo_setup(todo_setup):
@@ -85,6 +82,31 @@ def test_view_task_detail(todo_setup, admin_client):
assert response.status_code == 200
+def test_del_task(todo_setup, admin_user, client):
+ task = Task.objects.first()
+ url = reverse("todo:delete_task", kwargs={"task_id": task.id})
+ # View accepts POST, not GET
+ client.login(username="admin", password="password")
+ response = client.get(url)
+ assert response.status_code == 403
+ response = client.post(url)
+ assert not Task.objects.filter(id=task.id).exists()
+
+
+def test_task_toggle_done(todo_setup, admin_user, client):
+ task = Task.objects.first()
+ assert not task.completed
+ url = reverse("todo:task_toggle_done", kwargs={"task_id": task.id})
+ # View accepts POST, not GET
+ client.login(username="admin", password="password")
+ response = client.get(url)
+ assert response.status_code == 403
+
+ client.post(url)
+ task.refresh_from_db()
+ assert task.completed
+
+
def test_view_search(todo_setup, admin_client):
url = reverse("todo:search")
response = admin_client.get(url)
diff --git a/todo/views/delete_task.py b/todo/views/delete_task.py
index 9e3ec99..526e19c 100644
--- a/todo/views/delete_task.py
+++ b/todo/views/delete_task.py
@@ -16,20 +16,27 @@ def delete_task(request, task_id: int) -> HttpResponse:
Redirect to the list from which the task came.
"""
- task = get_object_or_404(Task, pk=task_id)
+ if request.method == "POST":
+ task = get_object_or_404(Task, pk=task_id)
- # Permissions
- if not (
- (task.created_by == request.user)
- or (task.assigned_to == request.user)
- or (task.task_list.group in request.user.groups.all())
- ):
+ redir_url = reverse(
+ "todo:list_detail",
+ kwargs={"list_id": task.task_list.id, "list_slug": task.task_list.slug},
+ )
+
+ # Permissions
+ if not (
+ (task.created_by == request.user)
+ or (request.user.is_superuser)
+ or (task.assigned_to == request.user)
+ or (task.task_list.group in request.user.groups.all())
+ ):
+ raise PermissionDenied
+
+ task.delete()
+
+ messages.success(request, "Task '{}' has been deleted".format(task.title))
+ return redirect(redir_url)
+
+ else:
raise PermissionDenied
-
- tlist = task.task_list
- task.delete()
-
- messages.success(request, "Task '{}' has been deleted".format(task.title))
- return redirect(
- reverse("todo:list_detail", kwargs={"list_id": tlist.id, "list_slug": tlist.slug})
- )
diff --git a/todo/views/list_lists.py b/todo/views/list_lists.py
index 7672eca..d8b7bea 100644
--- a/todo/views/list_lists.py
+++ b/todo/views/list_lists.py
@@ -20,7 +20,7 @@ def list_lists(request) -> HttpResponse:
searchform = SearchForm(auto_id=False)
# Make sure user belongs to at least one group.
- if request.user.groups.all().count() == 0:
+ if not request.user.groups.all().exists():
messages.warning(
request,
"You do not yet belong to any groups. Ask your administrator to add you to one.",
diff --git a/todo/views/toggle_done.py b/todo/views/toggle_done.py
index 6a3934e..fdc727a 100644
--- a/todo/views/toggle_done.py
+++ b/todo/views/toggle_done.py
@@ -17,23 +17,27 @@ def toggle_done(request, task_id: int) -> HttpResponse:
Redirect to the list from which the task came.
"""
- task = get_object_or_404(Task, pk=task_id)
+ if request.method == "POST":
+ task = get_object_or_404(Task, pk=task_id)
- # Permissions
- if not (
- (request.user.is_superuser)
- or (task.created_by == request.user)
- or (task.assigned_to == request.user)
- or (task.task_list.group in request.user.groups.all())
- ):
- raise PermissionDenied
-
- toggle_task_completed(task.id)
- messages.success(request, "Task status changed for '{}'".format(task.title))
-
- return redirect(
- reverse(
+ redir_url = reverse(
"todo:list_detail",
kwargs={"list_id": task.task_list.id, "list_slug": task.task_list.slug},
)
- )
+
+ # Permissions
+ if not (
+ (task.created_by == request.user)
+ or (request.user.is_superuser)
+ or (task.assigned_to == request.user)
+ or (task.task_list.group in request.user.groups.all())
+ ):
+ raise PermissionDenied
+
+ toggle_task_completed(task.id)
+ messages.success(request, "Task status changed for '{}'".format(task.title))
+
+ return redirect(redir_url)
+
+ else:
+ raise PermissionDenied