Django 2.0 compatibility (requirement)
- URLs to path() style - Misc updates - Namespaces all URL references - Removes dependency on AutoSlugField - Cleaner reversals - Cleaner docstrings
This commit is contained in:
parent
238e39085d
commit
90c41d1f29
13 changed files with 92 additions and 96 deletions
2
setup.py
2
setup.py
|
@ -99,7 +99,7 @@ setup(
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
tests_require=['tox'],
|
tests_require=['tox'],
|
||||||
install_requires=['django-autoslug', 'unidecode', ],
|
install_requires=['unidecode', ],
|
||||||
cmdclass={
|
cmdclass={
|
||||||
'clean': Clean,
|
'clean': Clean,
|
||||||
'test': Tox,
|
'test': Tox,
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Migration(migrations.Migration):
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
('date', models.DateTimeField(default=datetime.datetime.now)),
|
('date', models.DateTimeField(default=datetime.datetime.now)),
|
||||||
('body', models.TextField(blank=True)),
|
('body', models.TextField(blank=True)),
|
||||||
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
},
|
},
|
||||||
|
@ -37,8 +37,8 @@ class Migration(migrations.Migration):
|
||||||
('completed_date', models.DateField(null=True, blank=True)),
|
('completed_date', models.DateField(null=True, blank=True)),
|
||||||
('note', models.TextField(null=True, blank=True)),
|
('note', models.TextField(null=True, blank=True)),
|
||||||
('priority', models.PositiveIntegerField(max_length=3)),
|
('priority', models.PositiveIntegerField(max_length=3)),
|
||||||
('assigned_to', models.ForeignKey(related_name='todo_assigned_to', to=settings.AUTH_USER_MODEL)),
|
('assigned_to', models.ForeignKey(related_name='todo_assigned_to', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
|
||||||
('created_by', models.ForeignKey(related_name='todo_created_by', to=settings.AUTH_USER_MODEL)),
|
('created_by', models.ForeignKey(related_name='todo_created_by', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['priority'],
|
'ordering': ['priority'],
|
||||||
|
@ -51,7 +51,7 @@ class Migration(migrations.Migration):
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
('name', models.CharField(max_length=60)),
|
('name', models.CharField(max_length=60)),
|
||||||
('slug', models.SlugField(max_length=60, editable=False)),
|
('slug', models.SlugField(max_length=60, editable=False)),
|
||||||
('group', models.ForeignKey(to='auth.Group')),
|
('group', models.ForeignKey(to='auth.Group', on_delete=models.CASCADE)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['name'],
|
'ordering': ['name'],
|
||||||
|
@ -66,13 +66,13 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='item',
|
model_name='item',
|
||||||
name='list',
|
name='list',
|
||||||
field=models.ForeignKey(to='todo.List'),
|
field=models.ForeignKey(to='todo.List', on_delete=models.CASCADE),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='comment',
|
model_name='comment',
|
||||||
name='task',
|
name='task',
|
||||||
field=models.ForeignKey(to='todo.Item'),
|
field=models.ForeignKey(to='todo.Item', on_delete=models.CASCADE),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,17 +3,16 @@ import datetime
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.core.urlresolvers import reverse
|
from django.urls import reverse
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from autoslug import AutoSlugField
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class List(models.Model):
|
class List(models.Model):
|
||||||
name = models.CharField(max_length=60)
|
name = models.CharField(max_length=60)
|
||||||
slug = AutoSlugField(populate_from='name', editable=False, always_update=True)
|
slug = models.SlugField(default='',)
|
||||||
group = models.ForeignKey(Group)
|
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -33,13 +32,14 @@ class List(models.Model):
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Item(models.Model):
|
class Item(models.Model):
|
||||||
title = models.CharField(max_length=140)
|
title = models.CharField(max_length=140)
|
||||||
list = models.ForeignKey(List)
|
list = models.ForeignKey(List, on_delete=models.CASCADE)
|
||||||
created_date = models.DateField(auto_now=True)
|
created_date = models.DateField(auto_now=True)
|
||||||
due_date = models.DateField(blank=True, null=True, )
|
due_date = models.DateField(blank=True, null=True, )
|
||||||
completed = models.BooleanField(default=None)
|
completed = models.BooleanField(default=None)
|
||||||
completed_date = models.DateField(blank=True, null=True)
|
completed_date = models.DateField(blank=True, null=True)
|
||||||
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='todo_created_by')
|
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='todo_created_by', on_delete=models.CASCADE)
|
||||||
assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name='todo_assigned_to')
|
assigned_to = models.ForeignKey(
|
||||||
|
settings.AUTH_USER_MODEL, blank=True, null=True, related_name='todo_assigned_to', on_delete=models.CASCADE)
|
||||||
note = models.TextField(blank=True, null=True)
|
note = models.TextField(blank=True, null=True)
|
||||||
priority = models.PositiveIntegerField()
|
priority = models.PositiveIntegerField()
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ class Item(models.Model):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
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 item creation / completed date
|
||||||
def save(self):
|
def save(self):
|
||||||
|
@ -72,8 +72,8 @@ 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)
|
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||||
task = models.ForeignKey(Item)
|
task = models.ForeignKey(Item, 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)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<p><input type="submit" name="delete-confirm" value="Do it! →" class="todo-button"> </p>
|
<p><input type="submit" name="delete-confirm" value="Do it! →" class="todo-button"> </p>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<a href="{% url 'todo-incomplete_tasks' list.id list_slug %}">Return to list: {{ list.name }}</a>
|
<a href="{% url 'todo:incomplete_tasks' list.id list_slug %}">Return to list: {{ list.name }}</a>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>Sorry, you don't have permission to delete lists. Please contact your group administrator.</p>
|
<p>Sorry, you don't have permission to delete lists. Please contact your group administrator.</p>
|
||||||
|
|
|
@ -14,7 +14,7 @@ Note: {{ task.note }}
|
||||||
|
|
||||||
|
|
||||||
Task details/comments:
|
Task details/comments:
|
||||||
http://{{ site }}{% url 'todo-task_detail' task.id %}
|
http://{{ site }}{% url 'todo:task_detail' task.id %}
|
||||||
|
|
||||||
List {{ task.list.name }}:
|
List {{ task.list.name }}:
|
||||||
http://{{ site }}{% url 'todo-incomplete_tasks' task.list.id task.list.slug %}
|
http://{{ site }}{% url 'todo:incomplete_tasks' task.list.id task.list.slug %}
|
||||||
|
|
|
@ -9,8 +9,8 @@ Comment:
|
||||||
{% endautoescape %}
|
{% endautoescape %}
|
||||||
|
|
||||||
Task details/comments:
|
Task details/comments:
|
||||||
https://{{ site }}{% url 'todo-task_detail' task.id %}
|
https://{{ site }}{% url 'todo:task_detail' task.id %}
|
||||||
|
|
||||||
List {{ task.list.name }}:
|
List {{ task.list.name }}:
|
||||||
https://{{ site }}{% url 'todo-incomplete_tasks' task.list.id task.list.slug %}
|
https://{{ site }}{% url 'todo:incomplete_tasks' task.list.id task.list.slug %}
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,14 @@
|
||||||
<h3>{{ group.grouper }}</h3>
|
<h3>{{ group.grouper }}</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{% for item in group.list %}
|
{% for item in group.list %}
|
||||||
<li><a class="todo" href="{% url 'todo-incomplete_tasks' item.id item.slug %}">{{ item.name }} </a> ({{ item.incomplete_tasks.count }}/{{ item.item_set.count }})</li>
|
<li>
|
||||||
|
<a class="todo" href="{% url 'todo:incomplete_tasks' item.id item.slug %}">{{ item.name }}</a>
|
||||||
|
({{ item.incomplete_tasks.count }}/{{ item.item_set.count }})
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<p><a href="{% url 'todo-add_list' %}">Create new todo list</a></p>
|
<p><a href="{% url 'todo:add_list' %}">Create new todo list</a></p>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
<h2>{{found_items.count}} search results for term: "{{ query_string }}"</h2>
|
<h2>{{found_items.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_items %}
|
||||||
<p><strong><a href="{% url 'todo-task_detail' f.id %}">{{ f.title }}</a></strong><br />
|
<p><strong><a href="{% url 'todo:task_detail' f.id %}">{{ f.title }}</a></strong><br />
|
||||||
<span class="minor">
|
<span class="minor">
|
||||||
On list: <a href="{% url 'todo-incomplete_tasks' f.list.id f.list.slug %}">{{ f.list.name }}</a><br />
|
On list: <a href="{% url 'todo:incomplete_tasks' f.list.id f.list.slug %}">{{ f.list.name }}</a><br />
|
||||||
Assigned to: {% if f.assigned_to %}{{ f.assigned_to }}{% else %}Anyone{% endif %} (created by: {{ f.created_by }})<br />
|
Assigned to: {% if f.assigned_to %}{{ f.assigned_to }}{% else %}Anyone{% endif %} (created by: {{ f.created_by }})<br />
|
||||||
Complete: {{ f.completed|yesno:"Yes,No" }}
|
Complete: {{ f.completed|yesno:"Yes,No" }}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// data in a list. We pass that list as an object called "data" to a Django view
|
// data in a list. We pass that list as an object called "data" to a Django view
|
||||||
// to save the re-ordered data into the database.
|
// to save the re-ordered data into the database.
|
||||||
|
|
||||||
$.post("{% url 'todo-reorder_tasks' %}", data, "json");
|
$.post("{% url 'todo:reorder_tasks' %}", data, "json");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
{% for task in task_list %}
|
{% for task in task_list %}
|
||||||
<tr id="{{ task.id }}">
|
<tr id="{{ task.id }}">
|
||||||
<td><input type="checkbox" name="mark_done" value="{{ task.id }}" id="mark_done_{{ task.id }}"> </td>
|
<td><input type="checkbox" name="mark_done" value="{{ task.id }}" id="mark_done_{{ task.id }}"> </td>
|
||||||
<td><a href="{% url 'todo-task_detail' task.id %}">{{ task.title|truncatewords:20 }}</a></td>
|
<td><a href="{% url 'todo:task_detail' task.id %}">{{ task.title|truncatewords:20 }}</a></td>
|
||||||
<td>{{ task.created_date|date:"m/d/Y" }}</td>
|
<td>{{ task.created_date|date:"m/d/Y" }}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if task.overdue_status %}<span class="overdue">{% endif %}
|
{% if task.overdue_status %}<span class="overdue">{% endif %}
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
<td style="text-align:center;">{% if task.note %}≈{% endif %} </td>
|
<td style="text-align:center;">{% if task.note %}≈{% endif %} </td>
|
||||||
<td style="text-align:center;">{% if task.comment_set.all.count != 0 %}{{ task.comment_set.all.count }}{% endif %}</td>
|
<td style="text-align:center;">{% if task.comment_set.all.count != 0 %}{{ task.comment_set.all.count }}{% endif %}</td>
|
||||||
{% if list_slug == "mine" %}
|
{% if list_slug == "mine" %}
|
||||||
<td><a href="{% url 'todo-incomplete_tasks' task.list.id task.list.slug %}">{{ task.list }}</a></td>
|
<td><a href="{% url 'todo:incomplete_tasks' task.list.id task.list.slug %}">{{ task.list }}</a></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td><input type="checkbox" name="del_tasks" value="{{ task.id }}" id="del_task_{{ task.id }}"> </td>
|
<td><input type="checkbox" name="del_tasks" value="{{ task.id }}" id="del_task_{{ task.id }}"> </td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -118,7 +118,7 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p><input type="submit" name="mark_tasks_done" value="Continue..." class="todo-button"></p>
|
<p><input type="submit" name="mark_tasks_done" value="Continue..." class="todo-button"></p>
|
||||||
<p><a class="todo" href="{% url 'todo-completed_tasks' list_id list_slug %}">View completed tasks</a></p>
|
<p><a class="todo" href="{% url 'todo:completed_tasks' list_id list_slug %}">View completed tasks</a></p>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@
|
||||||
{% for task in completed_list %}
|
{% for task in completed_list %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><input type="checkbox" name="undo_completed_task" value="{{ task.id }}" id="id_undo_completed_task{{ task.id }}"> </td>
|
<td><input type="checkbox" name="undo_completed_task" value="{{ task.id }}" id="id_undo_completed_task{{ task.id }}"> </td>
|
||||||
<td><a href="{% url 'todo-task_detail' task.id %}">{{ task.title|truncatewords:20 }}</a></td>
|
<td><a href="{% url 'todo:task_detail' task.id %}">{{ task.title|truncatewords:20 }}</a></td>
|
||||||
<td>{{ task.created_date|date:"m/d/Y" }}</td>
|
<td>{{ task.created_date|date:"m/d/Y" }}</td>
|
||||||
<td>{{ task.completed_date|date:"m/d/Y" }}</td>
|
<td>{{ task.completed_date|date:"m/d/Y" }}</td>
|
||||||
<td style="text-align:center;">{% if task.note %}≈{% endif %} </td>
|
<td style="text-align:center;">{% if task.note %}≈{% endif %} </td>
|
||||||
|
@ -153,12 +153,12 @@
|
||||||
</table>
|
</table>
|
||||||
<p><input type="submit" name="deldonetasks" value="Continue..." class="todo-button"></p>
|
<p><input type="submit" name="deldonetasks" value="Continue..." class="todo-button"></p>
|
||||||
</form>
|
</form>
|
||||||
<p><a class="todo" href="{% url 'todo-incomplete_tasks' list_id list_slug %}">View incomplete tasks</a></p>
|
<p><a class="todo" href="{% url 'todo:incomplete_tasks' list_id list_slug %}">View incomplete tasks</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if user.is_staff %}
|
{% if user.is_staff %}
|
||||||
{% if list_slug != "mine" %}
|
{% if list_slug != "mine" %}
|
||||||
<p><a class="todo" href="{% url 'todo-del_list' list.id list_slug %}">Delete this list</a></p>
|
<p><a class="todo" href="{% url 'todo:del_list' list.id list_slug %}">Delete this list</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<p id="slideToggle" ><strong>→ Click to edit details ←</strong></p>
|
<p id="slideToggle" ><strong>→ Click to edit details ←</strong></p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<strong>In list:</strong> <a href="{% url 'todo-incomplete_tasks' task.list.id task.list.slug %}" class="showlink">{{ task.list }}</a><br />
|
<strong>In list:</strong> <a href="{% url 'todo:incomplete_tasks' task.list.id task.list.slug %}" class="showlink">{{ task.list }}</a><br />
|
||||||
<strong>Assigned to:</strong> {% if task.assigned_to %}{{ task.assigned_to.get_full_name }}{% else %}Anyone{% endif %}<br />
|
<strong>Assigned to:</strong> {% if task.assigned_to %}{{ task.assigned_to.get_full_name }}{% else %}Anyone{% endif %}<br />
|
||||||
<strong>Created by:</strong> {{ task.created_by.first_name }} {{ task.created_by.last_name }}<br />
|
<strong>Created by:</strong> {{ task.created_by.first_name }} {{ task.created_by.last_name }}<br />
|
||||||
<strong>Due date:</strong> {{ task.due_date }}<br />
|
<strong>Due date:</strong> {{ task.due_date }}<br />
|
||||||
|
|
35
todo/urls.py
35
todo/urls.py
|
@ -1,23 +1,26 @@
|
||||||
from django.conf.urls import url
|
from django.urls import path
|
||||||
|
|
||||||
from todo import views
|
from todo import views
|
||||||
|
|
||||||
|
app_name = 'todo'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', views.list_lists, name="todo-lists"),
|
path('', views.list_lists, name="lists"),
|
||||||
url(r'^mine/$', views.view_list, {'list_slug': 'mine'}, name="todo-mine"),
|
path('mine/', views.view_list, {'list_slug': 'mine'}, name="mine"),
|
||||||
url(r'^(?P<list_id>\d{1,4})/(?P<list_slug>[\w-]+)/delete$', views.del_list, name="todo-del_list"),
|
path('<int:list_id>/<str:list_slug>/delete$', views.del_list, name="del_list"),
|
||||||
url(r'^task/(?P<task_id>\d{1,6})$', views.view_task, name='todo-task_detail'),
|
path('task/<int:task_id>', views.view_task, name='task_detail'),
|
||||||
url(r'^(?P<list_id>\d{1,4})/(?P<list_slug>[\w-]+)$', views.view_list, name='todo-incomplete_tasks'),
|
path('<int:list_id>/<str:list_slug>', views.view_list, name='incomplete_tasks'),
|
||||||
url(r'^(?P<list_id>\d{1,4})/(?P<list_slug>[\w-]+)/completed$', views.view_list, {'view_completed': True},
|
path('<int:list_id>/<str:list_slug>/completed$', views.view_list, {'view_completed': True}, name='completed_tasks'),
|
||||||
name='todo-completed_tasks'),
|
path('add_list/', views.add_list, name="add_list"),
|
||||||
url(r'^add_list/$', views.add_list, name="todo-add_list"),
|
|
||||||
url(r'^search-post/$', views.search_post, name="todo-search-post"),
|
# FIXME need both of these?
|
||||||
url(r'^search/$', views.search, name="todo-search"),
|
path('search-post/', views.search_post, name="search-post"),
|
||||||
|
path('search/', views.search, name="search"),
|
||||||
|
|
||||||
# View reorder_tasks is only called by JQuery for drag/drop task ordering
|
# View reorder_tasks is only called by JQuery for drag/drop task ordering
|
||||||
url(r'^reorder_tasks/$', views.reorder_tasks, name="todo-reorder_tasks"),
|
path('reorder_tasks/', views.reorder_tasks, name="reorder_tasks"),
|
||||||
|
|
||||||
url(r'^ticket/add/$', views.external_add, name="todo-external-add"),
|
path('ticket/add/', views.external_add, name="external-add"),
|
||||||
url(r'^recent/added/$', views.view_list, {'list_slug': 'recent-add'}, name="todo-recently_added"),
|
path('recent/added/', views.view_list, {'list_slug': 'recent-add'}, name="recently_added"),
|
||||||
url(r'^recent/completed/$', views.view_list, {'list_slug': 'recent-complete'},
|
path('recent/completed/', views.view_list, {'list_slug': 'recent-complete'}, name="recently_completed"),
|
||||||
name="todo-recently_completed"),
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.template.loader import render_to_string
|
|
||||||
from django.contrib.sites.models import Site
|
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 todo.models import Item
|
from todo.models import Item
|
||||||
|
|
||||||
# Need for links in email templates
|
|
||||||
current_site = Site.objects.get_current()
|
|
||||||
|
|
||||||
|
|
||||||
def mark_done(request, done_items):
|
def mark_done(request, done_items):
|
||||||
# Check for items in the mark_done POST array. If present, change status to complete.
|
# Check for items in the mark_done POST array. If present, change status to complete.
|
||||||
|
@ -39,6 +37,7 @@ def del_tasks(request, deleted_items):
|
||||||
|
|
||||||
def send_notify_mail(request, new_task):
|
def send_notify_mail(request, new_task):
|
||||||
# Send email
|
# Send email
|
||||||
|
current_site = Site.objects.get_current()
|
||||||
email_subject = render_to_string("todo/email/assigned_subject.txt", {'task': new_task})
|
email_subject = render_to_string("todo/email/assigned_subject.txt", {'task': new_task})
|
||||||
email_body = render_to_string(
|
email_body = render_to_string(
|
||||||
"todo/email/assigned_body.txt",
|
"todo/email/assigned_body.txt",
|
||||||
|
|
|
@ -1,43 +1,39 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import user_passes_test, login_required
|
from django.contrib.auth.decorators import user_passes_test, login_required
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib import messages
|
from django.contrib.sites.models import Site
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import HttpResponseRedirect, HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render, redirect
|
||||||
from django.template import RequestContext
|
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
from django.urls import reverse
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.contrib.sites.models import Site
|
|
||||||
|
|
||||||
from todo import settings
|
from todo import settings
|
||||||
from todo.forms import AddListForm, AddItemForm, EditItemForm, AddExternalItemForm, SearchForm
|
from todo.forms import AddListForm, AddItemForm, EditItemForm, AddExternalItemForm, SearchForm
|
||||||
from todo.models import Item, List, Comment
|
from todo.models import Item, List, Comment
|
||||||
from todo.utils import mark_done, undo_completed_task, del_tasks, send_notify_mail
|
from todo.utils import mark_done, undo_completed_task, del_tasks, send_notify_mail
|
||||||
|
|
||||||
# Need for links in email templates
|
|
||||||
current_site = Site.objects.get_current()
|
|
||||||
|
|
||||||
|
|
||||||
def check_user_allowed(user):
|
def check_user_allowed(user):
|
||||||
"""
|
"""
|
||||||
Conditions for user_passes_test decorator.
|
Conditions for user_passes_test decorator.
|
||||||
"""
|
"""
|
||||||
if settings.STAFF_ONLY:
|
if settings.STAFF_ONLY:
|
||||||
return user.is_authenticated() and user.is_staff
|
return user.is_authenticated and user.is_staff
|
||||||
else:
|
else:
|
||||||
return user.is_authenticated()
|
return user.is_authenticated
|
||||||
|
|
||||||
|
|
||||||
@user_passes_test(check_user_allowed)
|
@user_passes_test(check_user_allowed)
|
||||||
def list_lists(request):
|
def list_lists(request):
|
||||||
|
"""Homepage view - list of lists a user can view, and ability to add a list.
|
||||||
"""
|
"""
|
||||||
Homepage view - list of lists a user can view, and ability to add a list.
|
|
||||||
"""
|
|
||||||
thedate = datetime.datetime.now()
|
thedate = datetime.datetime.now()
|
||||||
searchform = SearchForm(auto_id=False)
|
searchform = SearchForm(auto_id=False)
|
||||||
|
|
||||||
|
@ -64,15 +60,14 @@ def list_lists(request):
|
||||||
|
|
||||||
@user_passes_test(check_user_allowed)
|
@user_passes_test(check_user_allowed)
|
||||||
def del_list(request, list_id, list_slug):
|
def del_list(request, list_id, list_slug):
|
||||||
"""
|
"""Delete an entire list. Danger Will Robinson! Only staff members should be allowed to access this view.
|
||||||
Delete an entire list. Danger Will Robinson! Only staff members should be allowed to access this view.
|
|
||||||
"""
|
"""
|
||||||
list = get_object_or_404(List, slug=list_slug)
|
list = get_object_or_404(List, slug=list_slug)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
List.objects.get(id=list.id).delete()
|
List.objects.get(id=list.id).delete()
|
||||||
messages.success(request, "{list_name} is gone.".format(list_name=list.name))
|
messages.success(request, "{list_name} is gone.".format(list_name=list.name))
|
||||||
return HttpResponseRedirect(reverse('todo-lists'))
|
return redirect('todo:lists')
|
||||||
else:
|
else:
|
||||||
item_count_done = Item.objects.filter(list=list.id, completed=1).count()
|
item_count_done = Item.objects.filter(list=list.id, completed=1).count()
|
||||||
item_count_undone = Item.objects.filter(list=list.id, completed=0).count()
|
item_count_undone = Item.objects.filter(list=list.id, completed=0).count()
|
||||||
|
@ -83,8 +78,7 @@ def del_list(request, list_id, list_slug):
|
||||||
|
|
||||||
@user_passes_test(check_user_allowed)
|
@user_passes_test(check_user_allowed)
|
||||||
def view_list(request, list_id=0, list_slug=None, view_completed=False):
|
def view_list(request, list_id=0, list_slug=None, view_completed=False):
|
||||||
"""
|
"""Display and manage items in a list.
|
||||||
Display and manage items in a list.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Make sure the accessing user has permission to view this list.
|
# Make sure the accessing user has permission to view this list.
|
||||||
|
@ -142,7 +136,7 @@ def view_list(request, list_id=0, list_slug=None, view_completed=False):
|
||||||
send_notify_mail(request, new_task)
|
send_notify_mail(request, new_task)
|
||||||
|
|
||||||
messages.success(request, "New task \"{t}\" has been added.".format(t=new_task.title))
|
messages.success(request, "New task \"{t}\" has been added.".format(t=new_task.title))
|
||||||
return HttpResponseRedirect(request.path)
|
return redirect(request.path)
|
||||||
else:
|
else:
|
||||||
# Don't allow adding new tasks on some views
|
# Don't allow adding new tasks on some views
|
||||||
if list_slug != "mine" and list_slug != "recent-add" and list_slug != "recent-complete":
|
if list_slug != "mine" and list_slug != "recent-add" and list_slug != "recent-complete":
|
||||||
|
@ -156,8 +150,7 @@ def view_list(request, list_id=0, list_slug=None, view_completed=False):
|
||||||
|
|
||||||
@user_passes_test(check_user_allowed)
|
@user_passes_test(check_user_allowed)
|
||||||
def view_task(request, task_id):
|
def view_task(request, task_id):
|
||||||
"""
|
"""View task details. Allow task details to be edited.
|
||||||
View task details. Allow task details to be edited.
|
|
||||||
"""
|
"""
|
||||||
task = get_object_or_404(Item, pk=task_id)
|
task = get_object_or_404(Item, pk=task_id)
|
||||||
comment_list = Comment.objects.filter(task=task_id)
|
comment_list = Comment.objects.filter(task=task_id)
|
||||||
|
@ -185,6 +178,7 @@ def view_task(request, task_id):
|
||||||
c.save()
|
c.save()
|
||||||
|
|
||||||
# And email comment to all people who have participated in this thread.
|
# And email comment to all people who have participated in this thread.
|
||||||
|
current_site = Site.objects.get_current()
|
||||||
email_subject = render_to_string("todo/email/assigned_subject.txt", {'task': task})
|
email_subject = render_to_string("todo/email/assigned_subject.txt", {'task': task})
|
||||||
email_body = render_to_string(
|
email_body = render_to_string(
|
||||||
"todo/email/newcomment_body.txt",
|
"todo/email/newcomment_body.txt",
|
||||||
|
@ -207,7 +201,7 @@ def view_task(request, task_id):
|
||||||
|
|
||||||
messages.success(request, "The task has been edited.")
|
messages.success(request, "The task has been edited.")
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse('todo-incomplete_tasks', args=[task.list.id, task.list.slug]))
|
return redirect('todo:lists', args=[task.list.id, task.list.slug])
|
||||||
else:
|
else:
|
||||||
form = EditItemForm(instance=task)
|
form = EditItemForm(instance=task)
|
||||||
if task.due_date:
|
if task.due_date:
|
||||||
|
@ -223,8 +217,7 @@ def view_task(request, task_id):
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
@user_passes_test(check_user_allowed)
|
@user_passes_test(check_user_allowed)
|
||||||
def reorder_tasks(request):
|
def reorder_tasks(request):
|
||||||
"""
|
"""Handle task re-ordering (priorities) from JQuery drag/drop in view_list.html
|
||||||
Handle task re-ordering (priorities) from JQuery drag/drop in view_list.html
|
|
||||||
"""
|
"""
|
||||||
newtasklist = request.POST.getlist('tasktable[]')
|
newtasklist = request.POST.getlist('tasktable[]')
|
||||||
# First item in received list is always empty - remove it
|
# First item in received list is always empty - remove it
|
||||||
|
@ -245,14 +238,14 @@ def reorder_tasks(request):
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def external_add(request):
|
def external_add(request):
|
||||||
"""
|
"""Allow users who don't have access to the rest of the ticket system to file a ticket in a specific list.
|
||||||
Allow users who don't have access to the rest of the ticket system to file a ticket in a specific list.
|
|
||||||
Public tickets are unassigned unless settings.DEFAULT_ASSIGNEE exists.
|
Public tickets are unassigned unless settings.DEFAULT_ASSIGNEE exists.
|
||||||
"""
|
"""
|
||||||
if request.POST:
|
if request.POST:
|
||||||
form = AddExternalItemForm(request.POST)
|
form = AddExternalItemForm(request.POST)
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
current_site = Site.objects.get_current()
|
||||||
item = form.save(commit=False)
|
item = form.save(commit=False)
|
||||||
item.list_id = settings.DEFAULT_LIST_ID
|
item.list_id = settings.DEFAULT_LIST_ID
|
||||||
item.created_by = request.user
|
item.created_by = request.user
|
||||||
|
@ -270,7 +263,8 @@ def external_add(request):
|
||||||
|
|
||||||
messages.success(request, "Your trouble ticket has been submitted. We'll get back to you soon.")
|
messages.success(request, "Your trouble ticket has been submitted. We'll get back to you soon.")
|
||||||
|
|
||||||
return HttpResponseRedirect(settings.PUBLIC_SUBMIT_REDIRECT)
|
return redirect(settings.PUBLIC_SUBMIT_REDIRECT)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
form = AddExternalItemForm()
|
form = AddExternalItemForm()
|
||||||
|
|
||||||
|
@ -279,8 +273,7 @@ def external_add(request):
|
||||||
|
|
||||||
@user_passes_test(check_user_allowed)
|
@user_passes_test(check_user_allowed)
|
||||||
def add_list(request):
|
def add_list(request):
|
||||||
"""
|
"""Allow users to add a new todo list to the group they're in.
|
||||||
Allow users to add a new todo list to the group they're in.
|
|
||||||
"""
|
"""
|
||||||
if request.POST:
|
if request.POST:
|
||||||
form = AddListForm(request.user, request.POST)
|
form = AddListForm(request.user, request.POST)
|
||||||
|
@ -288,7 +281,8 @@ def add_list(request):
|
||||||
try:
|
try:
|
||||||
form.save()
|
form.save()
|
||||||
messages.success(request, "A new list has been added.")
|
messages.success(request, "A new list has been added.")
|
||||||
return HttpResponseRedirect(request.path)
|
return redirect('todo:lists')
|
||||||
|
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
messages.error(
|
messages.error(
|
||||||
request,
|
request,
|
||||||
|
@ -305,19 +299,17 @@ def add_list(request):
|
||||||
|
|
||||||
@user_passes_test(check_user_allowed)
|
@user_passes_test(check_user_allowed)
|
||||||
def search_post(request):
|
def search_post(request):
|
||||||
"""
|
"""Redirect POST'd search param to query GET string
|
||||||
Redirect POST'd search param to query GET string
|
|
||||||
"""
|
"""
|
||||||
if request.POST:
|
if request.POST:
|
||||||
q = request.POST.get('q')
|
q = request.POST.get('q')
|
||||||
url = reverse('todo-search') + "?q=" + q
|
url = reverse('todo:search') + "?q=" + q
|
||||||
return HttpResponseRedirect(url)
|
return redirect(url)
|
||||||
|
|
||||||
|
|
||||||
@user_passes_test(check_user_allowed)
|
@user_passes_test(check_user_allowed)
|
||||||
def search(request):
|
def search(request):
|
||||||
"""
|
"""Search for tasks
|
||||||
Search for tasks
|
|
||||||
"""
|
"""
|
||||||
if request.GET:
|
if request.GET:
|
||||||
|
|
||||||
|
@ -343,9 +335,8 @@ def search(request):
|
||||||
query_string = None
|
query_string = None
|
||||||
found_items = None
|
found_items = None
|
||||||
|
|
||||||
return render(
|
context = {
|
||||||
request,
|
'query_string': query_string,
|
||||||
'todo/search_results.html', {
|
'found_items': found_items
|
||||||
'query_string': query_string,
|
}
|
||||||
'found_items': found_items
|
return render(request, 'todo/search_results.html', context)
|
||||||
}, context_instance=RequestContext(request))
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue