diff options
Diffstat (limited to 'todolists/views.py')
-rw-r--r-- | todolists/views.py | 184 |
1 files changed, 114 insertions, 70 deletions
diff --git a/todolists/views.py b/todolists/views.py index 379189ab..b6d3c25f 100644 --- a/todolists/views.py +++ b/todolists/views.py @@ -1,81 +1,102 @@ -from django import forms +import json +from django import forms from django.http import HttpResponse from django.conf import settings from django.core.mail import send_mail -from django.shortcuts import get_list_or_404, get_object_or_404, redirect -from django.contrib.auth.decorators import login_required, permission_required +from django.shortcuts import (get_list_or_404, get_object_or_404, + redirect, render) from django.db import transaction from django.views.decorators.cache import never_cache from django.views.generic import DeleteView -from django.views.generic.simple import direct_to_template from django.template import Context, loader -from django.utils import simplejson +from django.utils.timezone import now -from main.models import Todolist, TodolistPkg, Package, Repo +from main.models import Package, Repo +from main.utils import find_unique_slug from packages.utils import attach_maintainers -from .utils import get_annotated_todolists +from .models import Todolist, TodolistPackage +from .utils import get_annotated_todolists, attach_staging + class TodoListForm(forms.ModelForm): - packages = forms.CharField(required=False, + raw = forms.CharField(label='Packages', required=False, help_text='(one per line)', widget=forms.Textarea(attrs={'rows': '20', 'cols': '60'})) - def clean_packages(self): - package_names = [s.strip() for s in - self.cleaned_data['packages'].split("\n")] - package_names = set(package_names) - packages = Package.objects.filter(pkgname__in=package_names).filter( - repo__testing=False, repo__staging=False).select_related( - 'arch', 'repo').order_by('arch') - return packages + def package_names(self): + return {s.strip() for s in self.cleaned_data['raw'].split("\n")} + + def packages(self): + return Package.objects.normal().filter( + pkgname__in=self.package_names(), + repo__testing=False, repo__staging=False).order_by('arch') class Meta: model = Todolist - fields = ('name', 'description') + fields = ('name', 'description', 'raw') + -@permission_required('main.change_todolistpkg') @never_cache -def flag(request, list_id, pkg_id): - todolist = get_object_or_404(Todolist, id=list_id) - pkg = get_object_or_404(TodolistPkg, id=pkg_id) - pkg.complete = not pkg.complete - pkg.save() +def flag(request, slug, pkg_id): + todolist = get_object_or_404(Todolist, slug=slug) + tlpkg = get_object_or_404(TodolistPackage, id=pkg_id, removed__isnull=True) + # TODO: none of this; require absolute value on submit + if tlpkg.status == TodolistPackage.INCOMPLETE: + tlpkg.status = TodolistPackage.COMPLETE + else: + tlpkg.status = TodolistPackage.INCOMPLETE + tlpkg.user = request.user + tlpkg.save(update_fields=('status', 'user', 'last_modified')) if request.is_ajax(): - return HttpResponse( - simplejson.dumps({'complete': pkg.complete}), - mimetype='application/json') + data = { + 'status': tlpkg.get_status_display(), + 'css_class': tlpkg.status_css_class(), + } + return HttpResponse(json.dumps(data), content_type='application/json') return redirect(todolist) -@login_required -def view(request, list_id): - todolist = get_object_or_404(Todolist, id=list_id) - svn_roots = Repo.objects.order_by().values_list( - 'svn_root', flat=True).distinct() + +def view_redirect(request, old_id): + todolist = get_object_or_404(Todolist, old_id=old_id) + return redirect(todolist, permanent=True) + + +def view(request, slug): + todolist = get_object_or_404(Todolist, slug=slug) + svn_roots = Repo.objects.values_list( + 'svn_root', flat=True).order_by().distinct() # we don't hold onto the result, but the objects are the same here, # so accessing maintainers in the template is now cheap - attach_maintainers(tp.pkg for tp in todolist.packages) - return direct_to_template(request, 'todolists/view.html', { + attach_maintainers(todolist.packages()) + attach_staging(todolist.packages(), todolist.pk) + arches = {tp.arch for tp in todolist.packages()} + repos = {tp.repo for tp in todolist.packages()} + return render(request, 'todolists/view.html', { 'list': todolist, 'svn_roots': svn_roots, + 'arches': sorted(arches), + 'repos': sorted(repos), }) -# really no need for login_required on this one... -def list_pkgbases(request, list_id, svn_root): + +def list_pkgbases(request, slug, svn_root): '''Used to make bulk moves of packages a lot easier.''' - todolist = get_object_or_404(Todolist, id=list_id) + todolist = get_object_or_404(Todolist, slug=slug) repos = get_list_or_404(Repo, svn_root=svn_root) - pkgbases = set(tp.pkg.pkgbase for tp in todolist.packages - if tp.pkg.repo in repos) - return HttpResponse('\n'.join(sorted(pkgbases)), - mimetype='text/plain') + pkgbases = TodolistPackage.objects.values_list( + 'pkgbase', flat=True).filter( + todolist=todolist, repo__in=repos, removed__isnull=True).order_by( + 'pkgbase').distinct() + return HttpResponse('\n'.join(pkgbases), content_type='text/plain') + -@login_required def todolist_list(request): - lists = get_annotated_todolists() - return direct_to_template(request, 'todolists/list.html', {'lists': lists}) + incomplete_only = request.user.is_anonymous() + lists = get_annotated_todolists(incomplete_only) + return render(request, 'todolists/list.html', {'lists': lists}) + -@permission_required('main.add_todolist') @never_cache def add(request): if request.POST: @@ -89,16 +110,17 @@ def add(request): page_dict = { 'title': 'Add Todo List', + 'description': '', 'form': form, 'submit_text': 'Create List' } - return direct_to_template(request, 'general_form.html', page_dict) + return render(request, 'general_form.html', page_dict) + # TODO: this calls for transaction management and async emailing -@permission_required('main.change_todolist') @never_cache -def edit(request, list_id): - todo_list = get_object_or_404(Todolist, id=list_id) +def edit(request, slug): + todo_list = get_object_or_404(Todolist, slug=slug) if request.POST: form = TodoListForm(request.POST, instance=todo_list) if form.is_valid(): @@ -107,14 +129,16 @@ def edit(request, list_id): return redirect(todo_list) else: form = TodoListForm(instance=todo_list, - initial={ 'packages': '\n'.join(todo_list.package_names) }) + initial={'packages': todo_list.raw}) page_dict = { 'title': 'Edit Todo List: %s' % todo_list.name, + 'description': '', 'form': form, 'submit_text': 'Save List' } - return direct_to_template(request, 'general_form.html', page_dict) + return render(request, 'general_form.html', page_dict) + class DeleteTodolist(DeleteView): model = Todolist @@ -122,36 +146,64 @@ class DeleteTodolist(DeleteView): template_name = 'todolists/todolist_confirm_delete.html' success_url = '/todo/' + @transaction.commit_on_success def create_todolist_packages(form, creator=None): - packages = form.cleaned_data['packages'] + package_names = form.package_names() + packages = form.packages() + timestamp = now() if creator: - # todo list is new + # todo list is new, populate creator and slug fields todolist = form.save(commit=False) todolist.creator = creator + todolist.slug = find_unique_slug(Todolist, todolist.name) todolist.save() - - old_packages = [] else: # todo list already existed form.save() todolist = form.instance - # first delete any packages not in the new list - for todo_pkg in todolist.packages: - if todo_pkg.pkg not in packages: - todo_pkg.delete() - # save the old package list so we know what to add - old_packages = [p.pkg for p in todolist.packages] + # first mark removed any packages not in the new list + to_remove = set() + for todo_pkg in todolist.packages(): + if todo_pkg.pkg and todo_pkg.pkg not in packages: + to_remove.add(todo_pkg.pk) + elif todo_pkg.pkgname not in package_names: + to_remove.add(todo_pkg.pk) + + TodolistPackage.objects.filter( + pk__in=to_remove).update(removed=timestamp) + # Add (or mark unremoved) any packages in the new packages list todo_pkgs = [] for package in packages: - if package not in old_packages: - todo_pkg = TodolistPkg.objects.create(list=todolist, pkg=package) + # ensure get_or_create uses the fields in our unique constraint + defaults = { + 'pkg': package, + 'pkgbase': package.pkgbase, + 'repo': package.repo, + } + todo_pkg, created = TodolistPackage.objects.get_or_create( + todolist=todolist, + pkgname=package.pkgname, + arch=package.arch, + defaults=defaults) + if created: todo_pkgs.append(todo_pkg) + else: + save = False + if todo_pkg.removed is not None: + todo_pkg.removed = None + save = True + if todo_pkg.pkg != package: + todo_pkg.pkg = package + save = True + if save: + todo_pkg.save() return todo_pkgs + def send_todolist_emails(todo_list, new_packages): '''Sends emails to package maintainers notifying them that packages have been added to a todo list.''' @@ -179,12 +231,4 @@ def send_todolist_emails(todo_list, new_packages): [maint], fail_silently=True) -def public_list(request): - todo_lists = Todolist.objects.incomplete() - # total hackjob, but it makes this a lot less query-intensive. - all_pkgs = [tp for tl in todo_lists for tp in tl.packages] - attach_maintainers([tp.pkg for tp in all_pkgs]) - return direct_to_template(request, "todolists/public_list.html", - {"todo_lists": todo_lists}) - # vim: set ts=4 sw=4 et: |