Rename Item model to Task

- With matching model, view, template changes
This commit is contained in:
Scot Hacker 2018-03-28 22:51:10 -07:00
parent a2d02b0a8c
commit d3d8d5e46c
15 changed files with 133 additions and 119 deletions

View file

@ -21,7 +21,6 @@ setup(
'License :: OSI Approved :: BSD License', 'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent', 'Operating System :: OS Independent',
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Topic :: Office/Business :: Groupware', 'Topic :: Office/Business :: Groupware',
'Topic :: Software Development :: Bug Tracking', 'Topic :: Software Development :: Bug Tracking',

View file

@ -1,8 +1,8 @@
from django.contrib import admin from django.contrib import admin
from todo.models import Item, TaskList, Comment from todo.models import Task, TaskList, Comment
class ItemAdmin(admin.ModelAdmin): class TaskAdmin(admin.ModelAdmin):
list_display = ('title', 'task_list', 'completed', 'priority', 'due_date') list_display = ('title', 'task_list', 'completed', 'priority', 'due_date')
list_filter = ('task_list',) list_filter = ('task_list',)
ordering = ('priority',) ordering = ('priority',)
@ -15,4 +15,4 @@ class CommentAdmin(admin.ModelAdmin):
admin.site.register(TaskList) admin.site.register(TaskList)
admin.site.register(Comment, CommentAdmin) admin.site.register(Comment, CommentAdmin)
admin.site.register(Item, ItemAdmin) admin.site.register(Task, TaskAdmin)

View file

@ -1,7 +1,7 @@
from django import forms from django import forms
from django.forms import ModelForm from django.forms import ModelForm
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from todo.models import Item, TaskList from todo.models import Task, TaskList
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
@ -21,7 +21,7 @@ class AddTaskListForm(ModelForm):
exclude = [] exclude = []
class AddEditItemForm(ModelForm): class AddEditTaskForm(ModelForm):
"""The picklist showing the users to which a new task can be assigned """The picklist showing the users to which a new task can be assigned
must find other members of the groups the current list belongs to.""" must find other members of the groups the current list belongs to."""
@ -43,11 +43,11 @@ class AddEditItemForm(ModelForm):
widget=forms.Textarea(), required=False) widget=forms.Textarea(), required=False)
class Meta: class Meta:
model = Item model = Task
exclude = [] exclude = []
class AddExternalItemForm(ModelForm): class AddExternalTaskForm(ModelForm):
"""Form to allow users who are not part of the GTD system to file a ticket.""" """Form to allow users who are not part of the GTD system to file a ticket."""
title = forms.CharField( title = forms.CharField(
@ -63,7 +63,7 @@ class AddExternalItemForm(ModelForm):
) )
class Meta: class Meta:
model = Item model = Task
exclude = ( exclude = (
'task_list', 'created_date', 'due_date', 'created_by', 'assigned_to', 'completed', 'completed_date', ) 'task_list', 'created_date', 'due_date', 'created_by', 'assigned_to', 'completed', 'completed_date', )

View file

@ -0,0 +1,19 @@
# Generated by Django 2.0.3 on 2018-03-28 22:40
from django.conf import settings
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('todo', '0005_auto_20180212_2325'),
]
operations = [
migrations.RenameModel(
old_name='Item',
new_name='Task',
),
]

View file

@ -1,14 +1,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
from django.db import models
from django.contrib.auth.models import Group
from django.urls import reverse
from django.utils.encoding import python_2_unicode_compatible
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import Group
from django.db import models
from django.urls import reverse
@python_2_unicode_compatible
class TaskList(models.Model): class TaskList(models.Model):
name = models.CharField(max_length=60) name = models.CharField(max_length=60)
slug = models.SlugField(default='',) slug = models.SlugField(default='',)
@ -25,8 +23,7 @@ class TaskList(models.Model):
unique_together = ("group", "slug") unique_together = ("group", "slug")
@python_2_unicode_compatible class Task(models.Model):
class Item(models.Model):
title = models.CharField(max_length=140) title = models.CharField(max_length=140)
task_list = models.ForeignKey(TaskList, on_delete=models.CASCADE, null=True) task_list = models.ForeignKey(TaskList, on_delete=models.CASCADE, null=True)
created_date = models.DateField(auto_now=True) created_date = models.DateField(auto_now=True)
@ -41,7 +38,7 @@ class Item(models.Model):
# Has due date for an instance of this object passed? # Has due date for an instance of this object passed?
def overdue_status(self): def overdue_status(self):
"Returns whether the item's due date has passed or not." "Returns whether the Tasks's due date has passed or not."
if self.due_date and datetime.date.today() > self.due_date: if self.due_date and datetime.date.today() > self.due_date:
return True return True
@ -51,25 +48,24 @@ class Item(models.Model):
def get_absolute_url(self): def get_absolute_url(self):
return reverse('todo:task_detail', kwargs={'task_id': self.id, }) return reverse('todo:task_detail', kwargs={'task_id': self.id, })
# Auto-set the item creation / completed date # Auto-set the Task creation / completed date
def save(self, **kwargs): def save(self, **kwargs):
# If Item is being marked complete, set the completed_date # If Task is being marked complete, set the completed_date
if self.completed: if self.completed:
self.completed_date = datetime.datetime.now() self.completed_date = datetime.datetime.now()
super(Item, self).save() super(Task, self).save()
class Meta: class Meta:
ordering = ["priority"] ordering = ["priority"]
@python_2_unicode_compatible
class Comment(models.Model): class Comment(models.Model):
""" """
Not using Django's built-in comments because we want to be able to save Not using Django's built-in comments because we want to be able to save
a comment and change task details at the same time. Rolling our own since it's easy. a comment and change task details at the same time. Rolling our own since it's easy.
""" """
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
task = models.ForeignKey(Item, on_delete=models.CASCADE) task = models.ForeignKey(Task, on_delete=models.CASCADE)
date = models.DateTimeField(default=datetime.datetime.now) date = models.DateTimeField(default=datetime.datetime.now)
body = models.TextField(blank=True) body = models.TextField(blank=True)

View file

@ -8,10 +8,10 @@
<p>Category tally:</p> <p>Category tally:</p>
<ul> <ul>
<li>Incomplete: {{ item_count_undone }} </li> <li>Incomplete: {{ task_count_undone }} </li>
<li>Complete: {{ item_count_done }} </li> <li>Complete: {{ task_count_done }} </li>
<li> <li>
<strong>Total: {{ item_count_total }}</strong> <strong>Total: {{ task_count_total }}</strong>
</li> </li>
</ul> </ul>

View file

@ -27,7 +27,7 @@
<div class="form-group"> <div class="form-group">
<label for="id_assigned_to">Assigned To</label> <label for="id_assigned_to">Assigned To</label>
{# See todo.forms.AddEditItemForm #} {# See todo.forms.AddEditTaskForm #}
{{form.assigned_to}} {{form.assigned_to}}
</div> </div>

View file

@ -14,7 +14,7 @@
<hr /> <hr />
{% endif %} {% endif %}
{% if items %} {% if tasks %}
{% if list_slug == "mine" %} {% if list_slug == "mine" %}
<h1>Tasks assigned to me (in all groups)</h1> <h1>Tasks assigned to me (in all groups)</h1>
{% else %} {% else %}
@ -37,7 +37,7 @@
<th>Del</th> <th>Del</th>
</tr> </tr>
{% for task in items %} {% for task in tasks %}
<tr id="{{ task.id }}"> <tr id="{{ task.id }}">
<td> <td>
<input type="checkbox" name="toggle_done_tasks" <input type="checkbox" name="toggle_done_tasks"
@ -80,7 +80,7 @@
</form> </form>
{% else %} {% else %}
<h4>No items on this list yet (add one!)</h4> <h4>No tasks on this list yet (add one!)</h4>
{% include 'todo/include/toggle_delete.html' %} {% include 'todo/include/toggle_delete.html' %}
{% endif %} {% endif %}

View file

@ -5,16 +5,16 @@
{% block content %} {% block content %}
<h1>Todo Lists</h1> <h1>Todo Lists</h1>
<p>{{ item_count }} items in {{ list_count }} list{{ list_count|pluralize }}</p> <p>{{ task_count }} tasks in {{ list_count }} list{{ list_count|pluralize }}</p>
{% regroup lists by group as section_list %} {% regroup lists by group as section_list %}
{% for group in section_list %} {% for group in section_list %}
<h3>Group: {{ group.grouper }}</h3> <h3>Group: {{ group.grouper }}</h3>
<ul class="list-group mb-4"> <ul class="list-group mb-4">
{% for item in group.list %} {% for task in group.list %}
<li class="list-group-item d-flex justify-content-between align-items-center"> <li class="list-group-item d-flex justify-content-between align-items-center">
<a href="{% url 'todo:list_detail' item.id item.slug %}">{{ item.name }}</a> <a href="{% url 'todo:list_detail' task.id task.slug %}">{{ task.name }}</a>
<span class="badge badge-primary badge-pill">{{ item.item_set.count }}</span> <span class="badge badge-primary badge-pill">{{ task.task_set.count }}</span>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

View file

@ -4,10 +4,10 @@
{% block content_title %}<h2 class="page_title">Search</h2>{% endblock %} {% block content_title %}<h2 class="page_title">Search</h2>{% endblock %}
{% block content %} {% block content %}
{% if found_items %} {% if found_tasks %}
<h2>{{found_items.count}} search results for term: "{{ query_string }}"</h2> <h2>{{found_tasks.count}} search results for term: "{{ query_string }}"</h2>
<div class="post_list"> <div class="post_list">
{% for f in found_items %} {% for f in found_tasks %}
<p> <p>
<strong> <strong>
<a href="{% url 'todo:task_detail' f.id %}">{{ f.title }}</a> <a href="{% url 'todo:task_detail' f.id %}">{{ f.title }}</a>

View file

@ -2,7 +2,7 @@ import pytest
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from todo.models import Item, TaskList from todo.models import Task, TaskList
@pytest.fixture @pytest.fixture
@ -13,14 +13,14 @@ def todo_setup(django_user_model):
u1 = django_user_model.objects.create_user(username="u1", password="password", email="u1@example.com") u1 = django_user_model.objects.create_user(username="u1", password="password", email="u1@example.com")
u1.groups.add(g1) u1.groups.add(g1)
tlist1 = TaskList.objects.create(group=g1, name="Zip", slug="zip") tlist1 = TaskList.objects.create(group=g1, name="Zip", slug="zip")
Item.objects.create(created_by=u1, title="Task 1", task_list=tlist1, priority=1) Task.objects.create(created_by=u1, title="Task 1", task_list=tlist1, priority=1)
Item.objects.create(created_by=u1, title="Task 2", task_list=tlist1, priority=2, completed=True) Task.objects.create(created_by=u1, title="Task 2", task_list=tlist1, priority=2, completed=True)
Item.objects.create(created_by=u1, title="Task 3", task_list=tlist1, priority=3) Task.objects.create(created_by=u1, title="Task 3", task_list=tlist1, priority=3)
g2 = Group.objects.create(name="Workgroup Two") g2 = Group.objects.create(name="Workgroup Two")
u2 = django_user_model.objects.create_user(username="u2", password="password", email="u2@example.com") u2 = django_user_model.objects.create_user(username="u2", password="password", email="u2@example.com")
u2.groups.add(g2) u2.groups.add(g2)
tlist2 = TaskList.objects.create(group=g2, name="Zap", slug="zap") tlist2 = TaskList.objects.create(group=g2, name="Zap", slug="zap")
Item.objects.create(created_by=u2, title="Task 1", task_list=tlist2, priority=1) Task.objects.create(created_by=u2, title="Task 1", task_list=tlist2, priority=1)
Item.objects.create(created_by=u2, title="Task 2", task_list=tlist2, priority=2, completed=True) Task.objects.create(created_by=u2, title="Task 2", task_list=tlist2, priority=2, completed=True)
Item.objects.create(created_by=u2, title="Task 3", task_list=tlist2, priority=3) Task.objects.create(created_by=u2, title="Task 3", task_list=tlist2, priority=3)

View file

@ -2,7 +2,7 @@ import pytest
from django.core import mail from django.core import mail
from todo.models import Item, Comment from todo.models import Task, Comment
from todo.utils import toggle_done, toggle_deleted, send_notify_mail, send_email_to_thread_participants from todo.utils import toggle_done, toggle_deleted, send_notify_mail, send_email_to_thread_participants
@ -15,7 +15,7 @@ def email_backend_setup(settings):
def test_toggle_done(todo_setup): def test_toggle_done(todo_setup):
"""Utility function takes an array of POSTed IDs and changes their `completed` status. """Utility function takes an array of POSTed IDs and changes their `completed` status.
""" """
u1_tasks = Item.objects.filter(created_by__username="u1") u1_tasks = Task.objects.filter(created_by__username="u1")
completed = u1_tasks.filter(completed=True) completed = u1_tasks.filter(completed=True)
incomplete = u1_tasks.filter(completed=False) incomplete = u1_tasks.filter(completed=False)
@ -38,13 +38,13 @@ def test_toggle_done(todo_setup):
def test_toggle_deleted(todo_setup): def test_toggle_deleted(todo_setup):
"""Unlike toggle_done, delete means delete, so it's not really a toggle. """Unlike toggle_done, delete means delete, so it's not really a toggle.
""" """
u1_tasks = Item.objects.filter(created_by__username="u1") u1_tasks = Task.objects.filter(created_by__username="u1")
assert u1_tasks.count() == 3 assert u1_tasks.count() == 3
t1 = u1_tasks.first() t1 = u1_tasks.first()
t2 = u1_tasks.last() t2 = u1_tasks.last()
toggle_deleted([t1.id, t2.id, ]) toggle_deleted([t1.id, t2.id, ])
u1_tasks = Item.objects.filter(created_by__username="u1") u1_tasks = Task.objects.filter(created_by__username="u1")
assert u1_tasks.count() == 1 assert u1_tasks.count() == 1
@ -56,7 +56,7 @@ def test_send_notify_mail_not_me(todo_setup, django_user_model, email_backend_se
u1 = django_user_model.objects.get(username="u1") u1 = django_user_model.objects.get(username="u1")
u2 = django_user_model.objects.get(username="u2") u2 = django_user_model.objects.get(username="u2")
task = Item.objects.filter(created_by=u1).first() task = Task.objects.filter(created_by=u1).first()
task.assigned_to = u2 task.assigned_to = u2
task.save() task.save()
send_notify_mail(task) send_notify_mail(task)
@ -68,7 +68,7 @@ def test_send_notify_mail_myself(todo_setup, django_user_model, email_backend_se
""" """
u1 = django_user_model.objects.get(username="u1") u1 = django_user_model.objects.get(username="u1")
task = Item.objects.filter(created_by=u1).first() task = Task.objects.filter(created_by=u1).first()
task.assigned_to = u1 task.assigned_to = u1
task.save() task.save()
send_notify_mail(task) send_notify_mail(task)
@ -80,7 +80,7 @@ def test_send_email_to_thread_participants(todo_setup, django_user_model, email_
Notification email should be sent to all three users.""" Notification email should be sent to all three users."""
u1 = django_user_model.objects.get(username="u1") u1 = django_user_model.objects.get(username="u1")
task = Item.objects.filter(created_by=u1).first() task = Task.objects.filter(created_by=u1).first()
u3 = django_user_model.objects.create_user(username="u3", password="zzz", email="u3@example.com") u3 = django_user_model.objects.create_user(username="u3", password="zzz", email="u3@example.com")
u4 = django_user_model.objects.create_user(username="u4", password="zzz", email="u4@example.com") u4 = django_user_model.objects.create_user(username="u4", password="zzz", email="u4@example.com")

View file

@ -3,7 +3,7 @@ import pytest
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.urls import reverse from django.urls import reverse
from todo.models import Item, TaskList from todo.models import Task, TaskList
""" """
First the "smoketests" - do they respond at all for a logged in admin user? First the "smoketests" - do they respond at all for a logged in admin user?
@ -15,7 +15,7 @@ After that, view contents and behaviors.
@pytest.mark.django_db @pytest.mark.django_db
def test_todo_setup(todo_setup): def test_todo_setup(todo_setup):
assert Item.objects.all().count() == 6 assert Task.objects.all().count() == 6
def test_view_list_lists(todo_setup, admin_client): def test_view_list_lists(todo_setup, admin_client):
@ -73,7 +73,7 @@ def test_view_add_list(todo_setup, admin_client):
def test_view_task_detail(todo_setup, admin_client): def test_view_task_detail(todo_setup, admin_client):
task = Item.objects.first() task = Task.objects.first()
url = reverse('todo:task_detail', kwargs={'task_id': task.id}) url = reverse('todo:task_detail', kwargs={'task_id': task.id})
response = admin_client.get(url) response = admin_client.get(url)
assert response.status_code == 200 assert response.status_code == 200
@ -131,7 +131,7 @@ def test_view_list_not_mine(todo_setup, client):
def test_view_task_mine(todo_setup, client): def test_view_task_mine(todo_setup, client):
# Users can always view their own tasks # Users can always view their own tasks
task = Item.objects.filter(created_by__username="u1").first() task = Task.objects.filter(created_by__username="u1").first()
client.login(username="u1", password="password") client.login(username="u1", password="password")
url = reverse('todo:task_detail', kwargs={'task_id': task.id}) url = reverse('todo:task_detail', kwargs={'task_id': task.id})
response = client.get(url) response = client.get(url)
@ -147,7 +147,7 @@ def test_view_task_my_group(todo_setup, client, django_user_model):
u2.groups.add(g1) u2.groups.add(g1)
# Now u2 should be able to view one of u1's tasks. # Now u2 should be able to view one of u1's tasks.
task = Item.objects.filter(created_by__username="u1").first() task = Task.objects.filter(created_by__username="u1").first()
url = reverse('todo:task_detail', kwargs={'task_id': task.id}) url = reverse('todo:task_detail', kwargs={'task_id': task.id})
client.login(username="u2", password="password") client.login(username="u2", password="password")
response = client.get(url) response = client.get(url)
@ -157,7 +157,7 @@ def test_view_task_my_group(todo_setup, client, django_user_model):
def test_view_task_not_in_my_group(todo_setup, client): def test_view_task_not_in_my_group(todo_setup, client):
# User canNOT view a task that isn't theirs if the two users are not in a shared group. # User canNOT view a task that isn't theirs if the two users are not in a shared group.
# For this we can use the fixture data as-is. # For this we can use the fixture data as-is.
task = Item.objects.filter(created_by__username="u1").first() task = Task.objects.filter(created_by__username="u1").first()
url = reverse('todo:task_detail', kwargs={'task_id': task.id}) url = reverse('todo:task_detail', kwargs={'task_id': task.id})
client.login(username="u2", password="password") client.login(username="u2", password="password")
response = client.get(url) response = client.get(url)

View file

@ -4,35 +4,35 @@ from django.contrib.sites.models import Site
from django.core.mail import send_mail from django.core.mail import send_mail
from django.template.loader import render_to_string from django.template.loader import render_to_string
from todo.models import Item, Comment from todo.models import Task, Comment
def toggle_done(item_ids): def toggle_done(task_ids):
"""Check for items in the mark_done POST array. If present, change status to complete. """Check for tasks in the mark_done POST array. If present, change status to complete.
Takes a list of task IDs. Returns list of status change strings. Takes a list of task IDs. Returns list of status change strings.
""" """
_ret = [] _ret = []
for item_id in item_ids: for task_id in task_ids:
i = Item.objects.get(id=item_id) i = Task.objects.get(id=task_id)
old_state = "completed" if i.completed else "incomplete" old_state = "completed" if i.completed else "incomplete"
i.completed = not i.completed # Invert the done state, either way i.completed = not i.completed # Invert the done state, either way
new_state = "completed" if i.completed else "incomplete" new_state = "completed" if i.completed else "incomplete"
i.completed_date = datetime.datetime.now() i.completed_date = datetime.datetime.now()
i.save() i.save()
_ret.append("Item \"{i}\" changed from {o} to {n}.".format(i=i.title, o=old_state, n=new_state)) _ret.append("Task \"{i}\" changed from {o} to {n}.".format(i=i.title, o=old_state, n=new_state))
return _ret return _ret
def toggle_deleted(deleted_item_ids): def toggle_deleted(deleted_task_ids):
"""Delete selected items. Returns list of status change strings. """Delete selected tasks. Returns list of status change strings.
""" """
_ret = [] _ret = []
for item_id in deleted_item_ids: for task_id in deleted_task_ids:
i = Item.objects.get(id=item_id) i = Task.objects.get(id=task_id)
_ret.append("Item \"{i}\" deleted.".format(i=i.title)) _ret.append("Task \"{i}\" deleted.".format(i=i.title))
i.delete() i.delete()
return _ret return _ret

View file

@ -14,8 +14,8 @@ from django.shortcuts import get_object_or_404, render, redirect
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from todo.forms import AddTaskListForm, AddEditItemForm, AddExternalItemForm, SearchForm from todo.forms import AddTaskListForm, AddEditTaskForm, AddExternalTaskForm, SearchForm
from todo.models import Item, TaskList, Comment from todo.models import Task, TaskList, Comment
from todo.utils import ( from todo.utils import (
toggle_done, toggle_done,
toggle_deleted, toggle_deleted,
@ -62,16 +62,16 @@ def list_lists(request) -> HttpResponse:
# superusers see all lists, so count shouldn't filter by just lists the admin belongs to # superusers see all lists, so count shouldn't filter by just lists the admin belongs to
if request.user.is_superuser: if request.user.is_superuser:
item_count = Item.objects.filter(completed=0).count() task_count = Task.objects.filter(completed=0).count()
else: else:
item_count = Item.objects.filter(completed=0).filter(task_list__group__in=request.user.groups.all()).count() task_count = Task.objects.filter(completed=0).filter(task_list__group__in=request.user.groups.all()).count()
context = { context = {
"lists": lists, "lists": lists,
"thedate": thedate, "thedate": thedate,
"searchform": searchform, "searchform": searchform,
"list_count": list_count, "list_count": list_count,
"item_count": item_count, "task_count": task_count,
} }
return render(request, 'todo/list_lists.html', context) return render(request, 'todo/list_lists.html', context)
@ -95,15 +95,15 @@ def del_list(request, list_id: int, list_slug: str) -> HttpResponse:
messages.success(request, "{list_name} is gone.".format(list_name=task_list.name)) messages.success(request, "{list_name} is gone.".format(list_name=task_list.name))
return redirect('todo:lists') return redirect('todo:lists')
else: else:
item_count_done = Item.objects.filter(task_list=task_list.id, completed=True).count() task_count_done = Task.objects.filter(task_list=task_list.id, completed=True).count()
item_count_undone = Item.objects.filter(task_list=task_list.id, completed=False).count() task_count_undone = Task.objects.filter(task_list=task_list.id, completed=False).count()
item_count_total = Item.objects.filter(task_list=task_list.id).count() task_count_total = Task.objects.filter(task_list=task_list.id).count()
context = { context = {
"task_list": task_list, "task_list": task_list,
"item_count_done": item_count_done, "task_count_done": task_count_done,
"item_count_undone": item_count_undone, "task_count_undone": task_count_undone,
"item_count_total": item_count_total, "task_count_total": task_count_total,
} }
return render(request, 'todo/del_list.html', context) return render(request, 'todo/del_list.html', context)
@ -111,37 +111,37 @@ def del_list(request, list_id: int, list_slug: str) -> HttpResponse:
@login_required @login_required
def list_detail(request, list_id=None, list_slug=None, view_completed=False): def list_detail(request, list_id=None, list_slug=None, view_completed=False):
"""Display and manage items in a todo list. """Display and manage tasks in a todo list.
""" """
# Defaults # Defaults
task_list = None task_list = None
form = None form = None
# Which items to show on this list view? # Which tasks to show on this list view?
if list_slug == "mine": if list_slug == "mine":
items = Item.objects.filter(assigned_to=request.user) tasks =Task.objects.filter(assigned_to=request.user)
else: else:
# Show a specific list, ensuring permissions. # Show a specific list, ensuring permissions.
task_list = get_object_or_404(TaskList, id=list_id) task_list = get_object_or_404(TaskList, id=list_id)
if task_list.group not in request.user.groups.all() and not request.user.is_staff: if task_list.group not in request.user.groups.all() and not request.user.is_staff:
raise PermissionDenied raise PermissionDenied
items = Item.objects.filter(task_list=task_list.id) tasks = Task.objects.filter(task_list=task_list.id)
# Additional filtering # Additional filtering
if view_completed: if view_completed:
items = items.filter(completed=True) tasks = tasks.filter(completed=True)
else: else:
items = items.filter(completed=False) tasks = tasks.filter(completed=False)
if request.POST: if request.POST:
# Process completed and deleted items on each POST # Process completed and deleted tasks on each POST
results_changed = toggle_done(request.POST.getlist('toggle_done_tasks')) results_changed = toggle_done(request.POST.getlist('toggle_done_tasks'))
for res in results_changed: for res in results_changed:
messages.success(request, res) messages.success(request, res)
results_changed = toggle_deleted(request, request.POST.getlist('toggle_deleted_tasks')) results_changed = toggle_deleted(request.POST.getlist('toggle_deleted_tasks'))
for res in results_changed: for res in results_changed:
messages.success(request, res) messages.success(request, res)
@ -150,7 +150,7 @@ def list_detail(request, list_id=None, list_slug=None, view_completed=False):
# ###################### # ######################
if request.POST.getlist('add_edit_task'): if request.POST.getlist('add_edit_task'):
form = AddEditItemForm(request.user, request.POST, initial={ form = AddEditTaskForm(request.user, request.POST, initial={
'assigned_to': request.user.id, 'assigned_to': request.user.id,
'priority': 999, 'priority': 999,
'task_list': task_list 'task_list': task_list
@ -168,7 +168,7 @@ def list_detail(request, list_id=None, list_slug=None, view_completed=False):
else: else:
# Don't allow adding new tasks on some views # Don't allow adding new tasks on some views
if list_slug not in ["mine", "recent-add", "recent-complete", ]: if list_slug not in ["mine", "recent-add", "recent-complete", ]:
form = AddEditItemForm(request.user, initial={ form = AddEditTaskForm(request.user, initial={
'assigned_to': request.user.id, 'assigned_to': request.user.id,
'priority': 999, 'priority': 999,
'task_list': task_list 'task_list': task_list
@ -179,7 +179,7 @@ def list_detail(request, list_id=None, list_slug=None, view_completed=False):
"list_slug": list_slug, "list_slug": list_slug,
"task_list": task_list, "task_list": task_list,
"form": form, "form": form,
"items": items, "tasks": tasks,
"view_completed": view_completed, "view_completed": view_completed,
} }
@ -191,10 +191,10 @@ def task_detail(request, task_id: int) -> HttpResponse:
"""View task details. Allow task details to be edited. Process new comments on task. """View task details. Allow task details to be edited. Process new comments on task.
""" """
task = get_object_or_404(Item, pk=task_id) task = get_object_or_404(Task, pk=task_id)
comment_list = Comment.objects.filter(task=task_id) comment_list = Comment.objects.filter(task=task_id)
# Ensure user has permission to view item. Admins can view all tasks. # Ensure user has permission to view task. Admins can view all tasks.
# Get the group this task belongs to, and check whether current user is a member of that group. # Get the group this task belongs to, and check whether current user is a member of that group.
if task.task_list.group not in request.user.groups.all() and not request.user.is_staff: if task.task_list.group not in request.user.groups.all() and not request.user.is_staff:
raise PermissionDenied raise PermissionDenied
@ -212,14 +212,14 @@ def task_detail(request, task_id: int) -> HttpResponse:
# Save task edits # Save task edits
if request.POST.get('add_edit_task'): if request.POST.get('add_edit_task'):
form = AddEditItemForm(request.user, request.POST, instance=task, initial={'task_list': task.task_list}) form = AddEditTaskForm(request.user, request.POST, instance=task, initial={'task_list': task.task_list})
if form.is_valid(): if form.is_valid():
form.save() form.save()
messages.success(request, "The task has been edited.") messages.success(request, "The task has been edited.")
return redirect('todo:list_detail', list_id=task.task_list.id, list_slug=task.task_list.slug) return redirect('todo:list_detail', list_id=task.task_list.id, list_slug=task.task_list.slug)
else: else:
form = AddEditItemForm(request.user, instance=task, initial={'task_list': task.task_list}) form = AddEditTaskForm(request.user, instance=task, initial={'task_list': task.task_list})
# Mark complete # Mark complete
if request.POST.get('toggle_done'): if request.POST.get('toggle_done'):
@ -251,15 +251,15 @@ def reorder_tasks(request) -> HttpResponse:
""" """
newtasklist = request.POST.getlist('tasktable[]') newtasklist = request.POST.getlist('tasktable[]')
if newtasklist: if newtasklist:
# First item in received list is always empty - remove it # First task in received list is always empty - remove it
del newtasklist[0] del newtasklist[0]
# Re-prioritize each item in list # Re-prioritize each task in list
i = 1 i = 1
for t in newtasklist: for t in newtasklist:
newitem = Item.objects.get(pk=t) newtask = Task.objects.get(pk=t)
newitem.priority = i newtask.priority = i
newitem.save() newtask.save()
i += 1 i += 1
# All views must return an httpresponse of some kind ... without this we get # All views must return an httpresponse of some kind ... without this we get
@ -306,33 +306,33 @@ def search(request) -> HttpResponse:
if request.GET: if request.GET:
query_string = '' query_string = ''
found_items = None found_tasks = None
if ('q' in request.GET) and request.GET['q'].strip(): if ('q' in request.GET) and request.GET['q'].strip():
query_string = request.GET['q'] query_string = request.GET['q']
found_items = Item.objects.filter( found_tasks = Task.objects.filter(
Q(title__icontains=query_string) | Q(title__icontains=query_string) |
Q(note__icontains=query_string) Q(note__icontains=query_string)
) )
else: else:
# What if they selected the "completed" toggle but didn't enter a query string? # What if they selected the "completed" toggle but didn't enter a query string?
# We still need found_items in a queryset so it can be "excluded" below. # We still need found_tasks in a queryset so it can be "excluded" below.
found_items = Item.objects.all() found_tasks = Task.objects.all()
if 'inc_complete' in request.GET: if 'inc_complete' in request.GET:
found_items = found_items.exclude(completed=True) found_tasks = found_tasks.exclude(completed=True)
else: else:
query_string = None query_string = None
found_items = None found_tasks =None
# Only include items that are in groups of which this user is a member: # Only include tasks that are in groups of which this user is a member:
if not request.user.is_superuser: if not request.user.is_superuser:
found_items = found_items.filter(task_list__group__in=request.user.groups.all()) found_tasks = found_tasks.filter(task_list__group__in=request.user.groups.all())
context = { context = {
'query_string': query_string, 'query_string': query_string,
'found_items': found_items 'found_tasks': found_tasks
} }
return render(request, 'todo/search_results.html', context) return render(request, 'todo/search_results.html', context)
@ -353,25 +353,25 @@ def external_add(request) -> HttpResponse:
raise RuntimeError("There is no TaskList with ID specified for DEFAULT_LIST_ID in settings.") raise RuntimeError("There is no TaskList with ID specified for DEFAULT_LIST_ID in settings.")
if request.POST: if request.POST:
form = AddExternalItemForm(request.POST) form = AddExternalTaskForm(request.POST)
if form.is_valid(): if form.is_valid():
current_site = Site.objects.get_current() current_site = Site.objects.get_current()
item = form.save(commit=False) task = form.save(commit=False)
item.task_list = TaskList.objects.get(id=settings.TODO_DEFAULT_LIST_ID) task.task_list = TaskList.objects.get(id=settings.TODO_DEFAULT_LIST_ID)
item.created_by = request.user task.created_by = request.user
if settings.TODO_DEFAULT_ASSIGNEE: if settings.TODO_DEFAULT_ASSIGNEE:
item.assigned_to = User.objects.get(username=settings.TODO_DEFAULT_ASSIGNEE) task.assigned_to = User.objects.get(username=settings.TODO_DEFAULT_ASSIGNEE)
item.save() task.save()
# Send email to assignee if we have one # Send email to assignee if we have one
if item.assigned_to: if task.assigned_to:
email_subject = render_to_string("todo/email/assigned_subject.txt", {'task': item.title}) email_subject = render_to_string("todo/email/assigned_subject.txt", {'task': task.title})
email_body = render_to_string("todo/email/assigned_body.txt", {'task': item, 'site': current_site, }) email_body = render_to_string("todo/email/assigned_body.txt", {'task': task, 'site': current_site, })
try: try:
send_mail( send_mail(
email_subject, email_body, item.created_by.email, email_subject, email_body, task.created_by.email,
[item.assigned_to.email, ], fail_silently=False) [task.assigned_to.email, ], fail_silently=False)
except ConnectionRefusedError: except ConnectionRefusedError:
messages.error(request, "Task saved but mail not sent. Contact your administrator.") messages.error(request, "Task saved but mail not sent. Contact your administrator.")
@ -380,7 +380,7 @@ def external_add(request) -> HttpResponse:
return redirect(settings.TODO_PUBLIC_SUBMIT_REDIRECT) return redirect(settings.TODO_PUBLIC_SUBMIT_REDIRECT)
else: else:
form = AddExternalItemForm(initial={'priority': 999}) form = AddExternalTaskForm(initial={'priority': 999})
context = { context = {
"form": form, "form": form,