coins-demo/todo/views.py
2015-09-02 23:30:04 +02:00

421 lines
17 KiB
Python

from django.shortcuts import render_to_response
from todo.models import Item, List, Comment
from todo.forms import AddListForm, AddItemForm, EditItemForm, AddExternalItemForm, SearchForm
from todo import settings
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
from django.contrib.sites.models import Site
from django.template.loader import render_to_string
from django.core.mail import send_mail
from django.contrib.auth.decorators import user_passes_test
from django.db import IntegrityError
from django.db.models import Q
from django.contrib import messages
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
import datetime
# Need for links in email templates
current_site = Site.objects.get_current()
def check_user_allowed(user):
"""
test for user_passes_test decorator
"""
if settings.STAFF_ONLY:
return user.is_authenticated() and user.is_staff
else:
return user.is_authenticated()
@user_passes_test(check_user_allowed)
def list_lists(request):
"""
Homepage view - list of lists a user can view, and ability to add a list.
"""
thedate = datetime.datetime.now()
searchform = SearchForm(auto_id=False)
# Make sure user belongs to at least one group.
group_count = request.user.groups.all().count()
if group_count == 0:
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.
# Superusers see all lists
if request.user.is_superuser:
list_list = List.objects.all().order_by('group', 'name')
else:
list_list = List.objects.filter(group__in=request.user.groups.all).order_by('group', 'name')
# Count everything
list_count = list_list.count()
# Note admin users see all lists, so count shouldn't filter by just lists the admin belongs to
if request.user.is_superuser:
item_count = Item.objects.filter(completed=0).count()
else:
item_count = Item.objects.filter(completed=0).filter(list__group__in=request.user.groups.all()).count()
return render_to_response('todo/list_lists.html', locals(), context_instance=RequestContext(request))
@user_passes_test(check_user_allowed)
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.
"""
if request.user.is_staff:
can_del = 1
# Get this list's object (to derive list.name, list.id, etc.)
list = get_object_or_404(List, slug=list_slug)
# If delete confirmation is in the POST, delete all items in the list, then kill the list itself
if request.method == 'POST':
# Can the items
del_items = Item.objects.filter(list=list.id)
for del_item in del_items:
del_item.delete()
# Kill the list
del_list = List.objects.get(id=list.id)
del_list.delete()
# A var to send to the template so we can show the right thing
list_killed = 1
else:
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_total = Item.objects.filter(list=list.id).count()
return render_to_response('todo/del_list.html', locals(), context_instance=RequestContext(request))
@user_passes_test(check_user_allowed)
def view_list(request, list_id=0, list_slug=None, view_completed=0):
"""
Display and manage items in a task list
"""
# Make sure the accessing user has permission to view this list.
# Always authorize the "mine" view. Admins can view/edit all lists.
if list_slug == "mine" or list_slug == "recent-add" or list_slug == "recent-complete":
auth_ok = 1
else:
list = get_object_or_404(List, slug=list_slug)
listid = list.id
# Check whether current user is a member of the group this list belongs to.
if list.group in request.user.groups.all() or request.user.is_staff or list_slug == "mine":
auth_ok = 1 # User is authorized for this view
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.")
# First check for items in the mark_done POST array. If present, change
# their status to complete.
if request.POST.getlist('mark_done'):
done_items = request.POST.getlist('mark_done')
# Iterate through array of done items and update its representation in the model
for thisitem in done_items:
p = Item.objects.get(id=thisitem)
p.completed = 1
p.completed_date = datetime.datetime.now()
p.save()
messages.success(request, "Item \"%s\" marked complete." % p.title)
# Undo: Set completed items back to incomplete
if request.POST.getlist('undo_completed_task'):
undone_items = request.POST.getlist('undo_completed_task')
for thisitem in undone_items:
p = Item.objects.get(id=thisitem)
p.completed = 0
p.save()
messages.success(request, "Previously completed task \"%s\" marked incomplete." % p.title)
# And delete any requested items
if request.POST.getlist('del_task'):
deleted_items = request.POST.getlist('del_task')
for thisitem in deleted_items:
p = Item.objects.get(id=thisitem)
p.delete()
messages.success(request, "Item \"%s\" deleted." % p.title)
# And delete any *already completed* items
if request.POST.getlist('del_completed_task'):
deleted_items = request.POST.getlist('del_completed_task')
for thisitem in deleted_items:
p = Item.objects.get(id=thisitem)
p.delete()
messages.success(request, "Deleted previously completed item \"%s\"." % p.title)
thedate = datetime.datetime.now()
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
if list_slug == "mine":
task_list = Item.objects.filter(assigned_to=request.user, completed=0)
completed_list = Item.objects.filter(assigned_to=request.user, completed=1)
elif list_slug == "recent-add":
# 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.
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)
elif list_slug == "recent-complete":
# 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]
# completed_list = Item.objects.filter(assigned_to=request.user, completed=1)
else:
task_list = Item.objects.filter(list=list.id, completed=0)
completed_list = Item.objects.filter(list=list.id, completed=1)
if request.POST.getlist('add_task'):
form = AddItemForm(list, request.POST, initial={
'assigned_to': request.user.id,
'priority': 999,
})
if form.is_valid():
# Save task first so we have a db object to play with
new_task = form.save()
# Send email alert only if the Notify checkbox is checked AND the assignee is not the same as the submittor
# Email subect and body format are handled by templates
if "notify" in request.POST:
if new_task.assigned_to != request.user:
# Send email
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, })
try:
send_mail(email_subject, email_body, new_task.created_by.email, [new_task.assigned_to.email],
fail_silently=False)
except:
messages.error(request, "Task saved but mail not sent. Contact your administrator.")
messages.success(request, "New task \"%s\" has been added." % new_task.title)
return HttpResponseRedirect(request.path)
else:
# 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":
form = AddItemForm(list, initial={
'assigned_to': request.user.id,
'priority': 999,
})
if request.user.is_staff:
can_del = 1
return render_to_response('todo/view_list.html', locals(), context_instance=RequestContext(request))
@user_passes_test(check_user_allowed)
def view_task(request, task_id):
"""
View task details. Allow task details to be edited.
"""
task = get_object_or_404(Item, pk=task_id)
comment_list = Comment.objects.filter(task=task_id)
# Before doing anything, make sure the accessing user has permission to view this item.
# Determine the group this task belongs to, and check whether current user is a member of that group.
# Admins can edit all tasks.
if task.list.group in request.user.groups.all() or request.user.is_staff:
auth_ok = 1
if request.POST:
form = EditItemForm(request.POST, instance=task)
if form.is_valid():
form.save()
# Also save submitted comment, if non-empty
if request.POST['comment-body']:
c = Comment(
author=request.user,
task=task,
body=request.POST['comment-body'],
)
c.save()
# 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_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.
recip_list = []
recip_list.append(task.created_by.email)
commenters = Comment.objects.filter(task=task)
for c in commenters:
recip_list.append(c.author.email)
# Eliminate duplicate emails with the Python set() function
recip_list = set(recip_list)
# Send message
try:
send_mail(email_subject, email_body, task.created_by.email, recip_list, fail_silently=False)
messages.success(request, "Comment sent to thread participants.")
except:
messages.error(request, "Comment saved but mail not sent. Contact your administrator.")
messages.success(request, "The task has been edited.")
return HttpResponseRedirect(reverse('todo-incomplete_tasks', args=[task.list.id, task.list.slug]))
else:
form = EditItemForm(instance=task)
if task.due_date:
thedate = task.due_date
else:
thedate = datetime.datetime.now()
else:
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))
@csrf_exempt
@user_passes_test(check_user_allowed)
def reorder_tasks(request):
"""
Handle task re-ordering (priorities) from JQuery drag/drop in view_list.html
"""
newtasklist = request.POST.getlist('tasktable[]')
# First item in received list is always empty - remove it
del newtasklist[0]
# Items arrive in order, so all we need to do is increment up from one, saving
# "i" as the new priority for the current object.
i = 1
for t in newtasklist:
newitem = Item.objects.get(pk=t)
newitem.priority = i
newitem.save()
i = i + 1
# All views must return an httpresponse of some kind ... without this we get
# error 500s in the log even though things look peachy in the browser.
return HttpResponse(status=201)
@login_required
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.
This is useful if, for example, a core web team are in a group that can file todos for each other,
but you also want students to be able to post trouble tickets to a list just for the sysadmin. This
way we don't have to put all users into a group that gives them access to the whole ticket system.
"""
if request.POST:
form = AddExternalItemForm(request.POST)
if form.is_valid():
# Don't commit the save until we've added in the fields we need to set
item = form.save(commit=False)
item.list_id = settings.DEFAULT_LIST_ID
item.created_by = request.user
item.assigned_to = User.objects.get(username=settings.DEFAULT_ASSIGNEE)
item.save()
# Send email
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, })
try:
send_mail(email_subject, email_body, item.created_by.email, [item.assigned_to.email],
fail_silently=False)
except:
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.")
return HttpResponseRedirect(reverse(settings.PUBLIC_SUBMIT_REDIRECT))
else:
form = AddExternalItemForm()
return render_to_response('todo/add_external_task.html', locals(), context_instance=RequestContext(request))
@user_passes_test(check_user_allowed)
def add_list(request):
"""
Allow users to add a new todo list to the group they're in.
"""
if request.POST:
form = AddListForm(request.user, request.POST)
if form.is_valid():
try:
form.save()
messages.success(request, "A new list has been added.")
return HttpResponseRedirect(request.path)
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.")
else:
if request.user.groups.all().count() == 1:
form = AddListForm(request.user, initial={"group": request.user.groups.all()[0]})
else:
form = AddListForm(request.user)
return render_to_response('todo/add_list.html', locals(), context_instance=RequestContext(request))
@user_passes_test(check_user_allowed)
def search_post(request):
"""
Redirect POST'd search param to query GET string
"""
if request.POST:
q = request.POST.get('q')
url = reverse('todo-search') + "?q=" + q
return HttpResponseRedirect(url)
@user_passes_test(check_user_allowed)
def search(request):
"""
Search for tasks
"""
if request.GET:
query_string = ''
found_items = None
if ('q' in request.GET) and request.GET['q'].strip():
query_string = request.GET['q']
found_items = Item.objects.filter(
Q(title__icontains=query_string) |
Q(note__icontains=query_string)
)
else:
# What if they selected the "completed" toggle but didn't type in a query string?
# In that case we still need found_items in a queryset so it can be "excluded" below.
found_items = Item.objects.all()
if 'inc_complete' in request.GET:
found_items = found_items.exclude(completed=True)
else:
query_string = None
found_items = None
return render_to_response('todo/search_results.html',
{'query_string': query_string, 'found_items': found_items},
context_instance=RequestContext(request))