Merge pull request #12 from bittner/master

Changed related_name in foreign key "created_by", reformatted code, readme and license
This commit is contained in:
Scot Hacker 2014-06-02 22:51:25 -07:00
commit 4ba595d9cb
14 changed files with 323 additions and 326 deletions

10
.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
# tools, IDEs, build folders
/.coverage/
/.idea/
/build/
/dist/
/docs/build/
/*.egg-info/
# Django and Python
*.py[cod]

27
LICENSE
View file

@ -1,12 +1,27 @@
Copyright (c) 2010, Scot Hacker, Birdhouse Arts Copyright (c) 2010, Scot Hacker, Birdhouse Arts and individual contributors.
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of Birdhouse Arts nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 3. Neither the name of Birdhouse Arts nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,3 +1,4 @@
include README include LICENSE
recursive-include todo/media * include README.rst
recursive-include todo/static *
recursive-include todo/templates * recursive-include todo/templates *

16
README
View file

@ -1,16 +0,0 @@
django-todo is a pluggable multi-user, multi-group task management and
assignment application for Django. It can serve as anything from a
personal to-do system to a complete, working ticketing system for organizations.
For documentation, see the django-todo wiki pages:
Overview and screenshots
http://github.com/shacker/django-todo/wiki/Overview-and-screenshots
Requirements and installation
http://github.com/shacker/django-todo/wiki/Requirements-and-Installation
This is version 1.3
Version history
http://github.com/shacker/django-todo/wiki/Version-history

21
README.rst Normal file
View file

@ -0,0 +1,21 @@
===========
django todo
===========
django-todo is a pluggable multi-user, multi-group task management and
assignment application for Django. It can serve as anything from a personal
to-do system to a complete, working ticketing system for organizations.
Documentation
=============
For documentation, see the django-todo wiki pages:
- `Overview and screenshots
<http://github.com/shacker/django-todo/wiki/Overview-and-screenshots>`_
- `Requirements and installation
<http://github.com/shacker/django-todo/wiki/Requirements-and-Installation>`_
- `Version history
<http://github.com/shacker/django-todo/wiki/Version-history>`_

12
setup.py Normal file → Executable file
View file

@ -1,12 +1,16 @@
#!/usr/bin/env python
from setuptools import setup, find_packages from setuptools import setup, find_packages
import todo
setup( setup(
name='django-todo', name='django-todo',
version='1.3', version=todo.__version__,
description='A multi-user, multi-group task management and assignment system for Django.', description='A multi-user, multi-group task management and assignment system for Django.',
author='Scot Hacker', author=todo.__author__,
author_email='shacker@birdhouse.org', author_email=todo.__email__,
url='http://github.com/shacker/django-todo', url=todo.__url__,
license=todo.__license__,
packages=find_packages(), packages=find_packages(),
classifiers=[ classifiers=[
'Development Status :: 4 - Beta', 'Development Status :: 4 - Beta',

View file

@ -0,0 +1,8 @@
"""django todo"""
__version__ = '1.4.dev'
__author__ = 'Scot Hacker'
__email__ = 'shacker@birdhouse.org'
__url__ = 'https://github.com/shacker/django-todo'
__license__ = 'BSD License'

View file

@ -1,6 +1,7 @@
from django.contrib import admin from django.contrib import admin
from todo.models import Item, User, List, Comment from todo.models import Item, User, List, Comment
class ItemAdmin(admin.ModelAdmin): class ItemAdmin(admin.ModelAdmin):
list_display = ('title', 'list', 'priority', 'due_date') list_display = ('title', 'list', 'priority', 'due_date')
list_filter = ('list',) list_filter = ('list',)

View file

@ -1,9 +1,8 @@
from django.db import models
from django import forms from django import forms
from django.forms import ModelForm from django.forms import ModelForm
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User, Group
from todo.models import Item, List from todo.models import Item, List
import datetime
class AddListForm(ModelForm): class AddListForm(ModelForm):
# The picklist showing allowable groups to which a new list can be added # The picklist showing allowable groups to which a new list can be added
@ -17,9 +16,7 @@ class AddListForm(ModelForm):
model = List model = List
class AddItemForm(ModelForm): class AddItemForm(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.
def __init__(self, task_list, *args, **kwargs): def __init__(self, task_list, *args, **kwargs):
@ -41,9 +38,7 @@ class AddItemForm(ModelForm):
model = Item model = Item
class EditItemForm(ModelForm): class EditItemForm(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.
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -55,7 +50,6 @@ class EditItemForm(ModelForm):
exclude = ('created_date', 'created_by',) exclude = ('created_date', 'created_by',)
class AddExternalItemForm(ModelForm): class AddExternalItemForm(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."""
@ -72,12 +66,9 @@ class AddExternalItemForm(ModelForm):
exclude = ('list', 'created_date', 'due_date', 'created_by', 'assigned_to',) exclude = ('list', 'created_date', 'due_date', 'created_by', 'assigned_to',)
class SearchForm(ModelForm): class SearchForm(ModelForm):
"""Search.""" """Search."""
q = forms.CharField( q = forms.CharField(
widget=forms.widgets.TextInput(attrs={'size': 35}) widget=forms.widgets.TextInput(attrs={'size': 35})
) )

View file

@ -1,11 +1,9 @@
from django.db import models from django.db import models
from django.forms.models import ModelForm
from django import forms
from django.contrib import admin
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User, Group
import string, datetime
from django.template.defaultfilters import slugify from django.template.defaultfilters import slugify
import datetime
class List(models.Model): class List(models.Model):
name = models.CharField(max_length=60) name = models.CharField(max_length=60)
@ -19,8 +17,6 @@ class List(models.Model):
super(List, self).save(*args, **kwargs) super(List, self).save(*args, **kwargs)
def __unicode__(self): def __unicode__(self):
return self.name return self.name
@ -39,9 +35,6 @@ class List(models.Model):
unique_together = ("group", "slug") unique_together = ("group", "slug")
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)
@ -49,7 +42,7 @@ class Item(models.Model):
due_date = models.DateField(blank=True, null=True, ) due_date = models.DateField(blank=True, null=True, )
completed = models.BooleanField() completed = models.BooleanField()
completed_date = models.DateField(blank=True, null=True) completed_date = models.DateField(blank=True, null=True)
created_by = models.ForeignKey(User, related_name='created_by') created_by = models.ForeignKey(User, related_name='todo_created_by')
assigned_to = models.ForeignKey(User, related_name='todo_assigned_to') assigned_to = models.ForeignKey(User, related_name='todo_assigned_to')
note = models.TextField(blank=True, null=True) note = models.TextField(blank=True, null=True)
priority = models.PositiveIntegerField(max_length=3) priority = models.PositiveIntegerField(max_length=3)
@ -77,7 +70,7 @@ class Item(models.Model):
class Comment(models.Model): class Comment(models.Model):
""" """
Not using Django's built-in comments becase 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(User) author = models.ForeignKey(User)

View file

@ -1,4 +1,3 @@
from django.core.exceptions import ImproperlyConfigured
from django.conf import settings from django.conf import settings
STAFF_ONLY = getattr(settings, 'TODO_STAFF_ONLY', False) STAFF_ONLY = getattr(settings, 'TODO_STAFF_ONLY', False)

View file

@ -31,7 +31,6 @@ a.showlink {
color: #474747; color: #474747;
} }
label { label {
display: block; display: block;
font-weight: bold; font-weight: bold;
@ -72,7 +71,7 @@ hr {
} }
table.nocolor, table.nocolor tr, table.nocolor td { table.nocolor, table.nocolor tr, table.nocolor td {
background-color: ; background-color: transparent;
} }
table#tasktable td, table#tasktable th { table#tasktable td, table#tasktable th {

View file

@ -1,12 +1,13 @@
from django.conf.urls import * from django.conf.urls import patterns, url
from django.contrib.auth import views as auth_views
urlpatterns = patterns('', urlpatterns = patterns(
'',
url(r'^mine/$', 'todo.views.view_list', {'list_slug': 'mine'}, name="todo-mine"), url(r'^mine/$', 'todo.views.view_list', {'list_slug': 'mine'}, name="todo-mine"),
url(r'^(?P<list_id>\d{1,4})/(?P<list_slug>[\w-]+)/delete$', 'todo.views.del_list', name="todo-del_list"), url(r'^(?P<list_id>\d{1,4})/(?P<list_slug>[\w-]+)/delete$', 'todo.views.del_list', name="todo-del_list"),
url(r'^task/(?P<task_id>\d{1,6})$', 'todo.views.view_task', name='todo-task_detail'), url(r'^task/(?P<task_id>\d{1,6})$', 'todo.views.view_task', name='todo-task_detail'),
url(r'^(?P<list_id>\d{1,4})/(?P<list_slug>[\w-]+)$', 'todo.views.view_list', name='todo-incomplete_tasks'), url(r'^(?P<list_id>\d{1,4})/(?P<list_slug>[\w-]+)$', 'todo.views.view_list', name='todo-incomplete_tasks'),
url(r'^(?P<list_id>\d{1,4})/(?P<list_slug>[\w-]+)/completed$', 'todo.views.view_list', {'view_completed':1},name='todo-completed_tasks'), url(r'^(?P<list_id>\d{1,4})/(?P<list_slug>[\w-]+)/completed$', 'todo.views.view_list', {'view_completed': 1},
name='todo-completed_tasks'),
url(r'^add_list/$', 'todo.views.add_list', name="todo-add_list"), url(r'^add_list/$', 'todo.views.add_list', name="todo-add_list"),
url(r'^search/$', 'todo.views.search', name="todo-search"), url(r'^search/$', 'todo.views.search', name="todo-search"),
url(r'^$', 'todo.views.list_lists', name="todo-lists"), url(r'^$', 'todo.views.list_lists', name="todo-lists"),
@ -16,6 +17,6 @@ urlpatterns = patterns('',
url(r'^ticket/add/$', 'todo.views.external_add', name="todo-external-add"), url(r'^ticket/add/$', 'todo.views.external_add', name="todo-external-add"),
url(r'^recent/added/$', 'todo.views.view_list', {'list_slug': 'recent-add'}, name="todo-recently_added"), url(r'^recent/added/$', 'todo.views.view_list', {'list_slug': 'recent-add'}, name="todo-recently_added"),
url(r'^recent/completed/$', 'todo.views.view_list',{'list_slug':'recent-complete'},name="todo-recently_completed"), url(r'^recent/completed/$', 'todo.views.view_list', {'list_slug': 'recent-complete'},
name="todo-recently_completed"),
) )

View file

@ -1,11 +1,9 @@
from django import forms
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from todo.models import Item, List, Comment from todo.models import Item, List, Comment
from todo.forms import AddListForm, AddItemForm, EditItemForm, AddExternalItemForm, SearchForm from todo.forms import AddListForm, AddItemForm, EditItemForm, AddExternalItemForm
from todo import settings from todo import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.contrib import auth
from django.template import RequestContext from django.template import RequestContext
from django.http import HttpResponseRedirect, HttpResponse from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
@ -25,7 +23,6 @@ current_site = Site.objects.get_current()
def check_user_allowed(user): def check_user_allowed(user):
""" """
test for user_passes_test decorator test for user_passes_test decorator
""" """
@ -35,20 +32,16 @@ def check_user_allowed(user):
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.
""" """
# Make sure user belongs to at least one group. # Make sure user belongs to at least one group.
group_count = request.user.groups.all().count() group_count = request.user.groups.all().count()
if group_count == 0: if group_count == 0:
messages.error(request, "You do not yet belong to any groups. Ask your administrator to add you to one.") messages.error(request, "You do not yet belong to any groups. Ask your administrator to add you to one.")
# Only show lists to the user that belong to groups they are members of. # Only show lists to the user that belong to groups they are members of.
# Superusers see all lists # Superusers see all lists
if request.user.is_superuser: if request.user.is_superuser:
@ -70,11 +63,9 @@ 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.
""" """
if request.user.is_staff: if request.user.is_staff:
can_del = 1 can_del = 1
@ -94,7 +85,6 @@ def del_list(request,list_id,list_slug):
# A var to send to the template so we can show the right thing # A var to send to the template so we can show the right thing
list_killed = 1 list_killed = 1
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()
@ -105,11 +95,9 @@ 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=0): def view_list(request, list_id=0, list_slug=None, view_completed=0):
""" """
Display and manage items in a task list Display and manage items in a task list
""" """
# Make sure the accessing user has permission to view this list. # Make sure the accessing user has permission to view this list.
# Always authorize the "mine" view. Admins can view/edit all lists. # Always authorize the "mine" view. Admins can view/edit all lists.
@ -125,7 +113,6 @@ def view_list(request,list_id=0,list_slug=None,view_completed=0):
else: # User does not belong to the group this list is attached to else: # User does not belong to the group this list is attached to
messages.error(request, "You do not have permission to view/edit this list.") messages.error(request, "You do not have permission to view/edit this list.")
# First check for items in the mark_done POST array. If present, change # First check for items in the mark_done POST array. If present, change
# their status to complete. # their status to complete.
if request.POST.getlist('mark_done'): if request.POST.getlist('mark_done'):
@ -138,7 +125,6 @@ def view_list(request,list_id=0,list_slug=None,view_completed=0):
p.save() p.save()
messages.success(request, "Item \"%s\" marked complete." % p.title) messages.success(request, "Item \"%s\" marked complete." % p.title)
# Undo: Set completed items back to incomplete # Undo: Set completed items back to incomplete
if request.POST.getlist('undo_completed_task'): if request.POST.getlist('undo_completed_task'):
undone_items = request.POST.getlist('undo_completed_task') undone_items = request.POST.getlist('undo_completed_task')
@ -148,7 +134,6 @@ def view_list(request,list_id=0,list_slug=None,view_completed=0):
p.save() p.save()
messages.success(request, "Previously completed task \"%s\" marked incomplete." % p.title) messages.success(request, "Previously completed task \"%s\" marked incomplete." % p.title)
# And delete any requested items # And delete any requested items
if request.POST.getlist('del_task'): if request.POST.getlist('del_task'):
deleted_items = request.POST.getlist('del_task') deleted_items = request.POST.getlist('del_task')
@ -165,11 +150,9 @@ def view_list(request,list_id=0,list_slug=None,view_completed=0):
p.delete() p.delete()
messages.success(request, "Deleted previously completed item \"%s\"." % p.title) messages.success(request, "Deleted previously completed item \"%s\"." % p.title)
thedate = datetime.datetime.now() thedate = datetime.datetime.now()
created_date = "%s-%s-%s" % (thedate.year, thedate.month, thedate.day) created_date = "%s-%s-%s" % (thedate.year, thedate.month, thedate.day)
# Get list of items with this list ID, or filter on items assigned to me, or recently added/completed # Get list of items with this list ID, or filter on items assigned to me, or recently added/completed
if list_slug == "mine": if list_slug == "mine":
task_list = Item.objects.filter(assigned_to=request.user, completed=0) task_list = Item.objects.filter(assigned_to=request.user, completed=0)
@ -178,20 +161,20 @@ def view_list(request,list_id=0,list_slug=None,view_completed=0):
elif list_slug == "recent-add": elif list_slug == "recent-add":
# We'll assume this only includes uncompleted items to avoid confusion. # We'll assume this only includes uncompleted items to avoid confusion.
# Only show items in lists that are in groups that the current user is also in. # Only show items in lists that are in groups that the current user is also in.
task_list = Item.objects.filter(list__group__in=(request.user.groups.all()),completed=0).order_by('-created_date')[:50] task_list = Item.objects.filter(list__group__in=(request.user.groups.all()), completed=0).order_by(
'-created_date')[:50]
# completed_list = Item.objects.filter(assigned_to=request.user, completed=1) # completed_list = Item.objects.filter(assigned_to=request.user, completed=1)
elif list_slug == "recent-complete": elif list_slug == "recent-complete":
# Only show items in lists that are in groups that the current user is also in. # Only show items in lists that are in groups that the current user is also in.
task_list = Item.objects.filter(list__group__in=request.user.groups.all(),completed=1).order_by('-completed_date')[:50] task_list = Item.objects.filter(list__group__in=request.user.groups.all(), completed=1).order_by(
'-completed_date')[:50]
# completed_list = Item.objects.filter(assigned_to=request.user, completed=1) # completed_list = Item.objects.filter(assigned_to=request.user, completed=1)
else: else:
task_list = Item.objects.filter(list=list.id, completed=0) task_list = Item.objects.filter(list=list.id, completed=0)
completed_list = Item.objects.filter(list=list.id, completed=1) completed_list = Item.objects.filter(list=list.id, completed=1)
if request.POST.getlist('add_task'): if request.POST.getlist('add_task'):
form = AddItemForm(list, request.POST, initial={ form = AddItemForm(list, request.POST, initial={
'assigned_to': request.user.id, 'assigned_to': request.user.id,
@ -209,17 +192,17 @@ def view_list(request,list_id=0,list_slug=None,view_completed=0):
# Send email # Send email
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("todo/email/assigned_body.txt", { 'task': new_task, 'site': current_site, }) email_body = render_to_string("todo/email/assigned_body.txt",
{'task': new_task, 'site': current_site, })
try: try:
send_mail(email_subject, email_body, new_task.created_by.email, [new_task.assigned_to.email], fail_silently=False) send_mail(email_subject, email_body, new_task.created_by.email, [new_task.assigned_to.email],
fail_silently=False)
except: except:
messages.error(request, "Task saved but mail not sent. Contact your administrator.") messages.error(request, "Task saved but mail not sent. Contact your administrator.")
messages.success(request, "New task \"%s\" has been added." % new_task.title) messages.success(request, "New task \"%s\" has been added." % new_task.title)
return HttpResponseRedirect(request.path) return HttpResponseRedirect(request.path)
else: else:
if list_slug != "mine" and list_slug != "recent-add" and list_slug != "recent-complete": # We don't allow adding a task on the "mine" view if list_slug != "mine" and list_slug != "recent-add" and list_slug != "recent-complete": # We don't allow adding a task on the "mine" view
form = AddItemForm(list, initial={ form = AddItemForm(list, initial={
@ -235,11 +218,9 @@ def view_list(request,list_id=0,list_slug=None,view_completed=0):
@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)
@ -267,7 +248,9 @@ def view_task(request,task_id):
# And email comment to all people who have participated in this thread. # And email comment to all people who have participated in this thread.
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("todo/email/newcomment_body.txt", { 'task': task, 'body':request.POST['comment-body'], 'site': current_site, 'user':request.user }) email_body = render_to_string("todo/email/newcomment_body.txt",
{'task': task, 'body': request.POST['comment-body'],
'site': current_site, 'user': request.user})
# Get list of all thread participants - task creator plus everyone who has commented on it. # Get list of all thread participants - task creator plus everyone who has commented on it.
recip_list = [] recip_list = []
@ -286,23 +269,18 @@ def view_task(request,task_id):
except: except:
messages.error(request, "Comment saved but mail not sent. Contact your administrator.") messages.error(request, "Comment saved but mail not sent. Contact your administrator.")
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 HttpResponseRedirect(reverse('todo-incomplete_tasks', 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:
thedate = task.due_date thedate = task.due_date
else: else:
thedate = datetime.datetime.now() thedate = datetime.datetime.now()
else: else:
messages.info(request, "You do not have permission to view/edit this task.") messages.info(request, "You do not have permission to view/edit this task.")
return render_to_response('todo/view_task.html', locals(), context_instance=RequestContext(request)) return render_to_response('todo/view_task.html', locals(), context_instance=RequestContext(request))
@ -312,7 +290,6 @@ 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
del newtasklist[0] del newtasklist[0]
@ -354,28 +331,25 @@ def external_add(request):
email_subject = render_to_string("todo/email/assigned_subject.txt", {'task': item.title}) email_subject = render_to_string("todo/email/assigned_subject.txt", {'task': item.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': item, 'site': current_site, })
try: try:
send_mail(email_subject, email_body, item.created_by.email, [item.assigned_to.email], fail_silently=False) send_mail(email_subject, email_body, item.created_by.email, [item.assigned_to.email],
fail_silently=False)
except: except:
messages.error(request, "Task saved but mail not sent. Contact your administrator.") messages.error(request, "Task saved but mail not sent. Contact your administrator.")
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(reverse('intranet_home')) return HttpResponseRedirect(reverse('intranet_home'))
else: else:
form = AddExternalItemForm() form = AddExternalItemForm()
return render_to_response('todo/add_external_task.html', locals(), context_instance=RequestContext(request)) return render_to_response('todo/add_external_task.html', locals(), context_instance=RequestContext(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)
if form.is_valid(): if form.is_valid():
@ -384,23 +358,20 @@ def add_list(request):
messages.success(request, "A new list has been added.") messages.success(request, "A new list has been added.")
return HttpResponseRedirect(request.path) return HttpResponseRedirect(request.path)
except IntegrityError: except IntegrityError:
messages.error(request, "There was a problem saving the new list. Most likely a list with the same name in the same group already exists." ) messages.error(request,
"There was a problem saving the new list. "
"Most likely a list with the same name in the same group already exists.")
else: else:
form = AddListForm(request.user) form = AddListForm(request.user)
return render_to_response('todo/add_list.html', locals(), context_instance=RequestContext(request)) return render_to_response('todo/add_list.html', locals(), context_instance=RequestContext(request))
@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:
query_string = '' query_string = ''
@ -428,4 +399,3 @@ def search(request):
return render_to_response('todo/search_results.html', return render_to_response('todo/search_results.html',
{'query_string': query_string, 'found_items': found_items}, {'query_string': query_string, 'found_items': found_items},
context_instance=RequestContext(request)) context_instance=RequestContext(request))