diff options
-rw-r--r-- | devel/views.py | 12 | ||||
-rw-r--r-- | sitestatic/archweb.css | 5 | ||||
-rw-r--r-- | sitestatic/archweb.js | 17 | ||||
-rw-r--r-- | templates/devel/index.html | 10 | ||||
-rw-r--r-- | templates/todolists/email_notification.txt | 2 | ||||
-rw-r--r-- | templates/todolists/list.html | 4 | ||||
-rw-r--r-- | templates/todolists/public_list.html | 18 | ||||
-rw-r--r-- | templates/todolists/view.html | 27 | ||||
-rw-r--r-- | todolists/urls.py | 2 | ||||
-rw-r--r-- | todolists/utils.py | 14 | ||||
-rw-r--r-- | todolists/views.py | 76 |
11 files changed, 97 insertions, 90 deletions
diff --git a/devel/views.py b/devel/views.py index 7d5947d1..e01590a0 100644 --- a/devel/views.py +++ b/devel/views.py @@ -20,11 +20,12 @@ from django.utils.http import http_date from django.utils.timezone import now from .forms import ProfileForm, UserProfileForm, NewUserForm -from main.models import Package, PackageFile, TodolistPkg +from main.models import Package, PackageFile from main.models import Arch, Repo from news.models import News from packages.models import PackageRelation, Signoff, FlagRequest, Depend from packages.utils import get_signoff_groups +from todolists.models import TodolistPackage from todolists.utils import get_annotated_todolists from .utils import get_annotated_maintainers, UserFinder @@ -41,10 +42,11 @@ def index(request): flagged = Package.objects.normal().filter( flag_date__isnull=False, pkgbase__in=inner_q).order_by('pkgname') - todopkgs = TodolistPkg.objects.select_related( - 'pkg', 'pkg__arch', 'pkg__repo').filter(complete=False) - todopkgs = todopkgs.filter(pkg__pkgbase__in=inner_q).order_by( - 'list__name', 'pkg__pkgname') + todopkgs = TodolistPackage.objects.select_related( + 'todolist', 'pkg', 'arch', 'repo').exclude( + status=TodolistPackage.COMPLETE) + todopkgs = todopkgs.filter(pkgbase__in=inner_q).order_by( + 'todolist__name', 'pkgname') todolists = get_annotated_todolists(incomplete_only=True) diff --git a/sitestatic/archweb.css b/sitestatic/archweb.css index 6d6e1569..cfa30f5e 100644 --- a/sitestatic/archweb.css +++ b/sitestatic/archweb.css @@ -999,6 +999,11 @@ ul.admin-actions { .todo-table .incomplete { color: red; } + +.todo-table .inprogress { + color: darkorange; +} + .todo-info { margin: 0; color: #999; } diff --git a/sitestatic/archweb.js b/sitestatic/archweb.js index 42efb3fa..4a02fb63 100644 --- a/sitestatic/archweb.js +++ b/sitestatic/archweb.js @@ -15,7 +15,12 @@ if (typeof $ !== 'undefined' && typeof $.tablesorter !== 'undefined') { id: 'todostatus', is: function(s) { return false; }, format: function(s) { - return s.match(/incomplete/i) ? 1 : 0; + if (s.match(/incomplete/i)) { + return 1; + } else if (s.match(/in-progress/i)) { + return 0.5; + } + return 0; }, type: 'numeric' }); @@ -304,13 +309,9 @@ function todolist_flag() { // TODO: fix usage of this var link = this; $.getJSON(link.href, function(data) { - if (data.complete) { - $(link).text('Complete').addClass( - 'complete').removeClass('incomplete'); - } else { - $(link).text('Incomplete').addClass( - 'incomplete').removeClass('complete'); - } + $(link).text(data.status).removeClass( + 'complete inprogress incomplete').addClass( + data.css_class.toLowerCase()); /* let tablesorter know the cell value has changed */ $('.results').trigger('updateCell', [$(link).closest('td')[0], false, null]); }); diff --git a/templates/devel/index.html b/templates/devel/index.html index a07a4190..57151041 100644 --- a/templates/devel/index.html +++ b/templates/devel/index.html @@ -59,11 +59,11 @@ <tbody> {% for todopkg in todopkgs %} <tr class="{% cycle 'odd' 'even' %}"> - <td><a href="{{ todopkg.list.get_absolute_url }}" - title="View todo list: {{ todopkg.list.name }}">{{ todopkg.list.name }}</a></td> + <td><a href="{{ todopkg.todolist.get_absolute_url }}" + title="View todo list: {{ todopkg.todolist.name }}">{{ todopkg.todolist.name }}</a></td> <td>{% pkg_details_link todopkg.pkg %}</td> - <td>{{ todopkg.pkg.repo.name }}</td> - <td>{{ todopkg.pkg.arch.name }}</td> + <td>{{ todopkg.repo.name }}</td> + <td>{{ todopkg.arch.name }}</td> <td>{{ todopkg.pkg.maintainers|join:', ' }}</td> </tr> {% empty %} @@ -90,7 +90,7 @@ <tr class="{% cycle 'odd' 'even' %}"> <td><a href="{{ todo.get_absolute_url }}" title="View todo list: {{ todo.name }}">{{ todo.name }}</a></td> - <td>{{ todo.date_added|date }}</td> + <td>{{ todo.created|date }}</td> <td>{{ todo.creator.get_full_name }}</td> <td class="wrap">{{ todo.description|urlize }}</td> <td>{{ todo.pkg_count }}</td> diff --git a/templates/todolists/email_notification.txt b/templates/todolists/email_notification.txt index 8b22b465..e454ec79 100644 --- a/templates/todolists/email_notification.txt +++ b/templates/todolists/email_notification.txt @@ -1,7 +1,7 @@ {% autoescape off %}The todo list "{{ todolist.name }}" has had the following packages added to it for which you are a maintainer: {% for tpkg in todo_packages %} -* {{ tpkg.pkg.repo.name|lower }}/{{ tpkg.pkg.pkgname }} ({{ tpkg.pkg.arch.name }}) - {{ tpkg.pkg.get_full_url }}{% endfor %} +* {{ tpkg.repo.name|lower }}/{{ tpkg.pkgname }} ({{ tpkg.arch.name }}) - {{ tpkg.pkg.get_full_url }}{% endfor %} Todo list information: Name: {{ todolist.name }} diff --git a/templates/todolists/list.html b/templates/todolists/list.html index 51f9b570..4e456d28 100644 --- a/templates/todolists/list.html +++ b/templates/todolists/list.html @@ -8,7 +8,7 @@ <h2>Package Todo Lists</h2> - {% if perms.main.add_todolist %} + {% if perms.todolists.add_todolist %} <ul class="admin-actions"> <li><a href="/todo/add/" title="Add new todo list">Add Todo List</a></li> </ul> @@ -31,7 +31,7 @@ <tr class="{% cycle 'odd' 'even' %}"> <td><a href="{{ list.get_absolute_url }}" title="View todo list: {{ list.name }}">{{ list.name }}</a></td> - <td>{{ list.date_added|date }}</td> + <td>{{ list.created|date }}</td> <td>{{ list.creator.get_full_name }}</td> <td class="wrap">{{ list.description|urlize }}</td> <td>{{ list.pkg_count }}</td> diff --git a/templates/todolists/public_list.html b/templates/todolists/public_list.html index 9e0e5234..41caf5b0 100644 --- a/templates/todolists/public_list.html +++ b/templates/todolists/public_list.html @@ -30,7 +30,7 @@ <div class="todo-list"> <a name="{{ list.id }}"></a> <h4>{{ list.name }}</h4> - <p class="todo-info">{{ list.date_added|date }} - {{ list.creator.get_full_name }}</p> + <p class="todo-info">{{ list.created|date }} - {{ list.creator.get_full_name }}</p> <div>{{ list.description|urlize|linebreaks }}</div> <table id="todo-pkglist-{{ list.id }}" class="results todo-table"> <thead> @@ -45,17 +45,11 @@ <tbody> {% for pkg in list.packages %} <tr class="{% cycle 'odd' 'even' %}"> - <td>{% pkg_details_link pkg.pkg %}</td> - <td>{{ pkg.pkg.arch.name }}</td> - <td>{{ pkg.pkg.repo.name|capfirst }}</td> - <td>{{ pkg.pkg.maintainers|join:', ' }}</td> - <td> - {% if pkg.complete %} - <span class="complete">Complete</span> - {% else %} - <span class="incomplete">Incomplete</span> - {% endif %} - </td> + <td>{% pkg_details_link pkg.pkg pkg.pkgname %}</td> + <td>{{ pkg.arch.name }}</td> + <td>{{ pkg.repo.name|capfirst }}</td> + <td>{{ pkg.maintainers|join:', ' }}</td> + <td><span class="{{ pkg.status_css_class }}">{{ pkg.get_status_display }}</span></td> </tr> {% endfor %} </tbody> diff --git a/templates/todolists/view.html b/templates/todolists/view.html index b6f59704..0f3475a2 100644 --- a/templates/todolists/view.html +++ b/templates/todolists/view.html @@ -10,17 +10,17 @@ <h2>Todo List: {{ list.name }}</h2> <ul class="admin-actions"> - {% if perms.main.delete_todolist %} + {% if perms.todolists.delete_todolist %} <li><a href="/todo/delete/{{list.id}}/" title="Delete this todo list">Delete Todo List</a></li> {% endif %} - {% if perms.main.change_todolist %} + {% if perms.todolists.change_todolist %} <li><a href="/todo/edit/{{list.id}}/" title="Edit this todo list">Edit Todo List</a></li> {% endif %} </ul> - <p class="todo-info">{{ list.date_added|date }} - {{ list.creator.get_full_name }}</p> + <p class="todo-info">{{ list.created|date }} - {{ list.creator.get_full_name }}</p> <div>{{list.description|urlize|linebreaks}}</div> @@ -68,27 +68,22 @@ </thead> <tbody> {% for pkg in list.packages %} - <tr class="{% cycle 'odd' 'even' %}{% if user in pkg.pkg.maintainers %} mine{% endif %} {{ pkg.pkg.arch.name }} {{ pkg.pkg.repo.name|lower }}"> - <td>{{ pkg.pkg.arch.name }}</td> - <td>{{ pkg.pkg.repo.name|capfirst }}</td> - <td>{% pkg_details_link pkg.pkg %}</td> + <tr class="{% cycle 'odd' 'even' %}{% if user in pkg.maintainers %} mine{% endif %} {{ pkg.arch.name }} {{ pkg.repo.name|lower }}"> + <td>{{ pkg.arch.name }}</td> + <td>{{ pkg.repo.name|capfirst }}</td> + <td>{% pkg_details_link pkg.pkg pkg.pkgname %}</td> {% if pkg.pkg.flag_date %} <td><span class="flagged">{{ pkg.pkg.full_version }}</span></td> {% else %} <td>{{ pkg.pkg.full_version }}</td> {% endif %} - <td>{{ pkg.pkg.maintainers|join:', ' }}</td> + <td>{{ pkg.maintainers|join:', ' }}</td> <td> - {% if perms.main.change_todolistpkg %} - {% if pkg.complete %} + {% if perms.todolist.change_todolistpackage %} <a href="/todo/flag/{{ list.id }}/{{ pkg.id }}/" - class="status-link complete" title="Toggle completion status">Complete</a> + class="status-link {{ pkg.status_css_class }}" title="Toggle completion status">{{ pkg.get_status_display }}</a> {% else %} - <a href="/todo/flag/{{ list.id }}/{{ pkg.id }}/" - class="status-link incomplete" title="Toggle completion status">Incomplete</a> - {% endif %} - {% else %} - {% if pkg.complete %}<span class="complete">Complete</span>{% else %}<span class="incomplete">Incomplete</span>{% endif %} + <span class="{{ pkg.status_css_class }}">{{ pkg.get_status_display }}</span> {% endif %} </td> </tr> diff --git a/todolists/urls.py b/todolists/urls.py index a379468f..81ac11f5 100644 --- a/todolists/urls.py +++ b/todolists/urls.py @@ -11,7 +11,7 @@ urlpatterns = patterns('todolists.views', (r'^edit/(?P<list_id>\d+)/$', 'edit'), (r'^flag/(\d+)/(\d+)/$', 'flag'), (r'^delete/(?P<pk>\d+)/$', - permission_required('main.delete_todolist')(DeleteTodolist.as_view())), + permission_required('todolists.delete_todolist')(DeleteTodolist.as_view())), ) # vim: set ts=4 sw=4 et: diff --git a/todolists/utils.py b/todolists/utils.py index 03c47931..d084c645 100644 --- a/todolists/utils.py +++ b/todolists/utils.py @@ -1,26 +1,26 @@ from django.db import connections, router from django.db.models import Count -from main.models import Todolist, TodolistPkg +from .models import Todolist, TodolistPackage def todo_counts(): sql = """ -SELECT list_id, count(*), sum(CASE WHEN complete THEN 1 ELSE 0 END) - FROM todolist_pkgs - GROUP BY list_id +SELECT todolist_id, count(*), sum(CASE WHEN status = %s THEN 1 ELSE 0 END) + FROM todolists_todolistpackage + GROUP BY todolist_id """ - database = router.db_for_write(TodolistPkg) + database = router.db_for_write(TodolistPackage) connection = connections[database] cursor = connection.cursor() - cursor.execute(sql) + cursor.execute(sql, [TodolistPackage.COMPLETE]) results = cursor.fetchall() return {row[0]: (row[1], row[2]) for row in results} def get_annotated_todolists(incomplete_only=False): lists = Todolist.objects.all().select_related( - 'creator').order_by('-date_added') + 'creator').order_by('-created') lookup = todo_counts() # tag each list with package counts diff --git a/todolists/views.py b/todolists/views.py index 9984ef9a..94164391 100644 --- a/todolists/views.py +++ b/todolists/views.py @@ -10,39 +10,45 @@ from django.views.decorators.cache import never_cache from django.views.generic import DeleteView from django.template import Context, loader -from main.models import Todolist, TodolistPkg, Package, Repo +from main.models import Package, Repo from packages.utils import attach_maintainers +from .models import Todolist, TodolistPackage from .utils import get_annotated_todolists + 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 packages(self): + package_names = {s.strip() for s in + self.cleaned_data['raw'].split("\n")} + return Package.objects.normal().filter(pkgname__in=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') +@permission_required('todolists.change_todolistpackage') @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() + tlpkg = get_object_or_404(TodolistPackage, id=pkg_id) + # TODO: none of this; require absolute value on submit + if tlpkg.status == TodolistPackage.INCOMPLETE: + tlpkg.status = TodolistPackage.COMPLETE + else: + tlpkg.status = TodolistPackage.INCOMPLETE + tlpkg.save() if request.is_ajax(): - return HttpResponse( - json.dumps({'complete': pkg.complete}), - mimetype='application/json') + data = { + 'status': tlpkg.get_status_display(), + 'css_class': tlpkg.status_css_class(), + } + return HttpResponse(json.dumps(data), mimetype='application/json') return redirect(todolist) @login_required @@ -52,9 +58,9 @@ def view(request, list_id): '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) - arches = {tp.pkg.arch for tp in todolist.packages} - repos = {tp.pkg.repo for tp in todolist.packages} + attach_maintainers(todolist.packages()) + 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, @@ -67,9 +73,9 @@ def list_pkgbases(request, list_id, svn_root): '''Used to make bulk moves of packages a lot easier.''' todolist = get_object_or_404(Todolist, id=list_id) repos = get_list_or_404(Repo, svn_root=svn_root) - pkgbases = {tp.pkg.pkgbase for tp in todolist.packages - if tp.pkg.repo in repos} - return HttpResponse('\n'.join(sorted(pkgbases)), + pkgbases = TodolistPackage.objects.values_list('pkgbase', flat=True).filter( + todolist=todolist, repo__in=repos).distinct().order_by('pkgbase') + return HttpResponse('\n'.join(pkgbases), mimetype='text/plain') @login_required @@ -77,7 +83,7 @@ def todolist_list(request): lists = get_annotated_todolists() return render(request, 'todolists/list.html', {'lists': lists}) -@permission_required('main.add_todolist') +@permission_required('todolists.add_todolist') @never_cache def add(request): if request.POST: @@ -98,7 +104,7 @@ def add(request): return render(request, 'general_form.html', page_dict) # TODO: this calls for transaction management and async emailing -@permission_required('main.change_todolist') +@permission_required('todolists.change_todolist') @never_cache def edit(request, list_id): todo_list = get_object_or_404(Todolist, id=list_id) @@ -110,7 +116,7 @@ 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, @@ -128,7 +134,7 @@ class DeleteTodolist(DeleteView): @transaction.commit_on_success def create_todolist_packages(form, creator=None): - packages = form.cleaned_data['packages'] + packages = form.packages() if creator: # todo list is new todolist = form.save(commit=False) @@ -140,18 +146,22 @@ def create_todolist_packages(form, creator=None): # todo list already existed form.save() todolist = form.instance + # first delete any packages not in the new list - for todo_pkg in todolist.packages: + 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] + old_packages = [todo_pkg.pkg for todo_pkg in todolist.packages()] todo_pkgs = [] for package in packages: if package not in old_packages: - todo_pkg = TodolistPkg.objects.create(list=todolist, pkg=package) + todo_pkg = TodolistPackage.objects.create(todolist=todolist, + pkg=package, pkgname=package.pkgname, + pkgbase=package.pkgbase, + arch=package.arch, repo=package.repo) todo_pkgs.append(todo_pkg) return todo_pkgs @@ -186,8 +196,8 @@ def send_todolist_emails(todo_list, new_packages): 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]) + all_pkgs = [tp for tl in todo_lists for tp in tl.packages()] + attach_maintainers(all_pkgs) return render(request, "todolists/public_list.html", {"todo_lists": todo_lists}) |