Convert task_delete and task_done views from GET to POST
This commit is contained in:
parent
891148e496
commit
01cab7a82f
8 changed files with 109 additions and 52 deletions
|
@ -168,6 +168,8 @@ The previous `tox` system was removed with the v2 release, since we no longer ai
|
||||||
|
|
||||||
# Version History
|
# 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.2.0** Re-instate enforcement of TODO_STAFF_ONLY setting
|
||||||
|
|
||||||
**2.1.1** Correct Python version requirement in documentation to Python 3.6
|
**2.1.1** Correct Python version requirement in documentation to Python 3.6
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
A multi-user, multi-group task management and assignment system for Django.
|
A multi-user, multi-group task management and assignment system for Django.
|
||||||
"""
|
"""
|
||||||
__version__ = '2.2.0'
|
__version__ = '2.2.1'
|
||||||
|
|
||||||
__author__ = 'Scot Hacker'
|
__author__ = 'Scot Hacker'
|
||||||
__email__ = 'shacker@birdhouse.org'
|
__email__ = 'shacker@birdhouse.org'
|
||||||
|
|
|
@ -52,13 +52,16 @@
|
||||||
{% if task.assigned_to %}{{ task.assigned_to }}{% else %}Anyone{% endif %}
|
{% if task.assigned_to %}{{ task.assigned_to }}{% else %}Anyone{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url "todo:task_toggle_done" task.id %}" class="btn btn-info btn-sm">
|
<form method="post" action="{% url "todo:task_toggle_done" task.id %}" role="form">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button class="btn btn-info btn-sm" type="submit" name="toggle_done">
|
||||||
{% if view_completed %}
|
{% if view_completed %}
|
||||||
Not Done
|
Not Done
|
||||||
{% else %}
|
{% else %}
|
||||||
Done
|
Done
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</button>
|
||||||
|
</form>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -12,21 +12,40 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<ul class="list-group">
|
<div class="mb-2">
|
||||||
<li class="list-group-item">
|
|
||||||
<form action="" method="post">
|
<button
|
||||||
|
class="btn btn-sm btn-primary"
|
||||||
|
id="EditTaskButton"
|
||||||
|
type="button"
|
||||||
|
data-toggle="collapse"
|
||||||
|
data-target="#AddEditTask"
|
||||||
|
>
|
||||||
|
Edit Task
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<form method="post" action="{% url "todo:task_toggle_done" task.id %}" role="form" style="display:inline;">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
<div style="display:inline;">
|
||||||
<button class="btn btn-sm btn-primary" id="EditTaskButton" type="button"
|
<button class="btn btn-info btn-sm" type="submit" name="toggle_done">
|
||||||
data-toggle="collapse" data-target="#AddEditTask">Edit Task</button>
|
|
||||||
|
|
||||||
<a href="{% url "todo:task_toggle_done" task.id %}" class="btn btn-info btn-sm">
|
|
||||||
{% if task.completed %} Mark Not Done {% else %} Mark Done {% endif %}
|
{% if task.completed %} Mark Not Done {% else %} Mark Done {% endif %}
|
||||||
</a>
|
</button>
|
||||||
|
</div>
|
||||||
<a href="{% url "todo:delete_task" task.id %}" class="btn btn-danger btn-sm">Delete</a>
|
|
||||||
</form>
|
</form>
|
||||||
</li>
|
|
||||||
|
<form method="post" action="{% url "todo:delete_task" task.id %}" role="form" style="display:inline;">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div style="display:inline;">
|
||||||
|
<button class="btn btn-danger btn-sm" type="submit" name="submit_delete">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="list-group">
|
||||||
|
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<strong>Assigned to:</strong>
|
<strong>Assigned to:</strong>
|
||||||
{% if task.assigned_to %} {{ task.assigned_to.get_full_name }} {% else %} Anyone {% endif %}
|
{% if task.assigned_to %} {{ task.assigned_to.get_full_name }} {% else %} Anyone {% endif %}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import bleach
|
import bleach
|
||||||
import json
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
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.
|
After that, view contents and behaviors.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ### SMOKETESTS ###
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_todo_setup(todo_setup):
|
def test_todo_setup(todo_setup):
|
||||||
|
@ -85,6 +82,31 @@ def test_view_task_detail(todo_setup, admin_client):
|
||||||
assert response.status_code == 200
|
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):
|
def test_view_search(todo_setup, admin_client):
|
||||||
url = reverse("todo:search")
|
url = reverse("todo:search")
|
||||||
response = admin_client.get(url)
|
response = admin_client.get(url)
|
||||||
|
|
|
@ -16,20 +16,27 @@ def delete_task(request, task_id: int) -> HttpResponse:
|
||||||
Redirect to the list from which the task came.
|
Redirect to the list from which the task came.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
task = get_object_or_404(Task, pk=task_id)
|
task = get_object_or_404(Task, pk=task_id)
|
||||||
|
|
||||||
|
redir_url = reverse(
|
||||||
|
"todo:list_detail",
|
||||||
|
kwargs={"list_id": task.task_list.id, "list_slug": task.task_list.slug},
|
||||||
|
)
|
||||||
|
|
||||||
# Permissions
|
# Permissions
|
||||||
if not (
|
if not (
|
||||||
(task.created_by == request.user)
|
(task.created_by == request.user)
|
||||||
|
or (request.user.is_superuser)
|
||||||
or (task.assigned_to == request.user)
|
or (task.assigned_to == request.user)
|
||||||
or (task.task_list.group in request.user.groups.all())
|
or (task.task_list.group in request.user.groups.all())
|
||||||
):
|
):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
tlist = task.task_list
|
|
||||||
task.delete()
|
task.delete()
|
||||||
|
|
||||||
messages.success(request, "Task '{}' has been deleted".format(task.title))
|
messages.success(request, "Task '{}' has been deleted".format(task.title))
|
||||||
return redirect(
|
return redirect(redir_url)
|
||||||
reverse("todo:list_detail", kwargs={"list_id": tlist.id, "list_slug": tlist.slug})
|
|
||||||
)
|
else:
|
||||||
|
raise PermissionDenied
|
||||||
|
|
|
@ -20,7 +20,7 @@ def list_lists(request) -> HttpResponse:
|
||||||
searchform = SearchForm(auto_id=False)
|
searchform = SearchForm(auto_id=False)
|
||||||
|
|
||||||
# Make sure user belongs to at least one group.
|
# 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(
|
messages.warning(
|
||||||
request,
|
request,
|
||||||
"You do not yet belong to any groups. Ask your administrator to add you to one.",
|
"You do not yet belong to any groups. Ask your administrator to add you to one.",
|
||||||
|
|
|
@ -17,12 +17,18 @@ def toggle_done(request, task_id: int) -> HttpResponse:
|
||||||
Redirect to the list from which the task came.
|
Redirect to the list from which the task came.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
task = get_object_or_404(Task, pk=task_id)
|
task = get_object_or_404(Task, pk=task_id)
|
||||||
|
|
||||||
|
redir_url = reverse(
|
||||||
|
"todo:list_detail",
|
||||||
|
kwargs={"list_id": task.task_list.id, "list_slug": task.task_list.slug},
|
||||||
|
)
|
||||||
|
|
||||||
# Permissions
|
# Permissions
|
||||||
if not (
|
if not (
|
||||||
(request.user.is_superuser)
|
(task.created_by == request.user)
|
||||||
or (task.created_by == request.user)
|
or (request.user.is_superuser)
|
||||||
or (task.assigned_to == request.user)
|
or (task.assigned_to == request.user)
|
||||||
or (task.task_list.group in request.user.groups.all())
|
or (task.task_list.group in request.user.groups.all())
|
||||||
):
|
):
|
||||||
|
@ -31,9 +37,7 @@ def toggle_done(request, task_id: int) -> HttpResponse:
|
||||||
toggle_task_completed(task.id)
|
toggle_task_completed(task.id)
|
||||||
messages.success(request, "Task status changed for '{}'".format(task.title))
|
messages.success(request, "Task status changed for '{}'".format(task.title))
|
||||||
|
|
||||||
return redirect(
|
return redirect(redir_url)
|
||||||
reverse(
|
|
||||||
"todo:list_detail",
|
else:
|
||||||
kwargs={"list_id": task.task_list.id, "list_slug": task.task_list.slug},
|
raise PermissionDenied
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue