summaryrefslogtreecommitdiffstats
path: root/apps/patchwork/views
diff options
context:
space:
mode:
Diffstat (limited to 'apps/patchwork/views')
-rw-r--r--apps/patchwork/views/__init__.py90
-rw-r--r--apps/patchwork/views/base.py66
-rw-r--r--apps/patchwork/views/bundle.py158
-rw-r--r--apps/patchwork/views/patch.py180
-rw-r--r--apps/patchwork/views/user.py201
5 files changed, 695 insertions, 0 deletions
diff --git a/apps/patchwork/views/__init__.py b/apps/patchwork/views/__init__.py
new file mode 100644
index 0000000..2636d29
--- /dev/null
+++ b/apps/patchwork/views/__init__.py
@@ -0,0 +1,90 @@
+# Patchwork - automated patch tracking system
+# Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
+#
+# This file is part of the Patchwork package.
+#
+# Patchwork is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Patchwork is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Patchwork; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+from base import *
+from patchwork.utils import Order, get_patch_ids, set_patches
+from patchwork.paginator import Paginator
+from patchwork.forms import MultiplePatchForm
+
+def generic_list(request, project, view,
+ view_args = {}, filter_settings = [], patches = None):
+
+ context = PatchworkRequestContext(request,
+ list_view = view,
+ list_view_params = view_args)
+
+ context.project = project
+ order = Order(request.REQUEST.get('order'))
+
+ form = MultiplePatchForm(project)
+
+ if request.method == 'POST' and \
+ request.POST.get('form') == 'patchlistform':
+ action = request.POST.get('action', None)
+ if action:
+ action = action.lower()
+
+ # special case: the user may have hit enter in the 'create bundle'
+ # text field, so if non-empty, assume the create action:
+ if request.POST.get('bundle_name', False):
+ action = 'create'
+
+ ps = []
+ for patch_id in get_patch_ids(request.POST):
+ try:
+ patch = Patch.objects.get(id = patch_id)
+ except Patch.DoesNotExist:
+ pass
+ ps.append(patch)
+
+ (errors, form) = set_patches(request.user, action, request.POST, \
+ ps, context)
+ if errors:
+ context['errors'] = errors
+
+ if not (request.user.is_authenticated() and \
+ project in request.user.get_profile().maintainer_projects.all()):
+ form = None
+
+ for (filterclass, setting) in filter_settings:
+ if isinstance(setting, dict):
+ context.filters.set_status(filterclass, **setting)
+ elif isinstance(setting, list):
+ context.filters.set_status(filterclass, *setting)
+ else:
+ context.filters.set_status(filterclass, setting)
+
+ if not patches:
+ patches = Patch.objects.filter(project=project)
+
+ patches = context.filters.apply(patches)
+ patches = patches.order_by(order.query())
+
+ paginator = Paginator(request, patches)
+
+ context.update({
+ 'page': paginator.current_page,
+ 'patchform': form,
+ 'project': project,
+ 'order': order,
+ })
+
+ return context
+
diff --git a/apps/patchwork/views/base.py b/apps/patchwork/views/base.py
new file mode 100644
index 0000000..16fa5db
--- /dev/null
+++ b/apps/patchwork/views/base.py
@@ -0,0 +1,66 @@
+# Patchwork - automated patch tracking system
+# Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
+#
+# This file is part of the Patchwork package.
+#
+# Patchwork is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Patchwork is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Patchwork; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+from patchwork.models import Patch, Project, Person, RegistrationRequest
+from patchwork.filters import Filters
+from patchwork.forms import RegisterForm, LoginForm, PatchForm
+from django.shortcuts import render_to_response, get_object_or_404
+from django.http import HttpResponse, HttpResponseRedirect
+from django.db import transaction
+from django.contrib.auth.models import User
+from django.contrib.auth.decorators import login_required
+import django.core.urlresolvers
+from patchwork.requestcontext import PatchworkRequestContext
+from django.core import serializers
+
+def projects(request):
+ context = PatchworkRequestContext(request)
+ projects = Project.objects.all()
+
+ if projects.count() == 1:
+ return HttpResponseRedirect(
+ django.core.urlresolvers.reverse('patchwork.views.patch.list',
+ kwargs = {'project_id': projects[0].linkname}))
+
+ context['projects'] = projects
+ return render_to_response('patchwork/projects.html', context)
+
+def project(request, project_id):
+ context = PatchworkRequestContext(request)
+ project = get_object_or_404(Project, linkname = project_id)
+ context.project = project
+
+ context['maintainers'] = User.objects.filter( \
+ userprofile__maintainer_projects = project)
+ context['n_patches'] = Patch.objects.filter(project = project,
+ archived = False).count()
+ context['n_archived_patches'] = Patch.objects.filter(project = project,
+ archived = True).count()
+
+ return render_to_response('patchwork/project.html', context)
+
+def submitter_complete(request):
+ search = request.GET.get('q', '')
+ response = HttpResponse(mimetype = "text/plain")
+ if len(search) > 3:
+ queryset = Person.objects.filter(name__icontains = search)
+ json_serializer = serializers.get_serializer("json")()
+ json_serializer.serialize(queryset, ensure_ascii=False, stream=response)
+ return response
diff --git a/apps/patchwork/views/bundle.py b/apps/patchwork/views/bundle.py
new file mode 100644
index 0000000..be6a937
--- /dev/null
+++ b/apps/patchwork/views/bundle.py
@@ -0,0 +1,158 @@
+# Patchwork - automated patch tracking system
+# Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
+#
+# This file is part of the Patchwork package.
+#
+# Patchwork is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Patchwork is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Patchwork; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth.models import User
+from django.shortcuts import render_to_response, get_object_or_404
+from patchwork.requestcontext import PatchworkRequestContext
+from django.http import HttpResponse, HttpResponseRedirect
+import django.core.urlresolvers
+from patchwork.models import Patch, Bundle, Project
+from patchwork.utils import get_patch_ids
+from patchwork.forms import BundleForm
+from patchwork.views import generic_list
+from patchwork.filters import DelegateFilter
+from patchwork.paginator import Paginator
+
+@login_required
+def setbundle(request):
+ context = PatchworkRequestContext(request)
+
+ bundle = None
+
+ if request.method == 'POST':
+ action = request.POST.get('action', None)
+ if action is None:
+ pass
+ elif action == 'create':
+ project = get_object_or_404(Project,
+ id = request.POST.get('project'))
+ bundle = Bundle(owner = request.user, project = project,
+ name = request.POST['name'])
+ bundle.save()
+ patch_id = request.POST.get('patch_id', None)
+ if patch_id:
+ patch = get_object_or_404(Patch, id = patch_id)
+ bundle.patches.add(patch)
+ bundle.save()
+ elif action == 'add':
+ bundle = get_object_or_404(Bundle,
+ owner = request.user, id = request.POST['id'])
+ bundle.save()
+
+ patch_id = request.get('patch_id', None)
+ if patch_id:
+ patch_ids = patch_id
+ else:
+ patch_ids = get_patch_ids(request.POST)
+
+ for id in patch_ids:
+ try:
+ patch = Patch.objects.get(id = id)
+ bundle.patches.add(patch)
+ except ex:
+ pass
+
+ bundle.save()
+ elif action == 'delete':
+ try:
+ bundle = Bundle.objects.get(owner = request.user,
+ id = request.POST['id'])
+ bundle.delete()
+ except Exception:
+ pass
+
+ bundle = None
+
+ else:
+ bundle = get_object_or_404(Bundle, owner = request.user,
+ id = request.POST['bundle_id'])
+
+ if 'error' in context:
+ pass
+
+ if bundle:
+ return HttpResponseRedirect(
+ django.core.urlresolvers.reverse(
+ 'patchwork.views.bundle.bundle',
+ kwargs = {'bundle_id': bundle.id}
+ )
+ )
+ else:
+ return HttpResponseRedirect(
+ django.core.urlresolvers.reverse(
+ 'patchwork.views.bundle.list')
+ )
+
+@login_required
+def bundle(request, bundle_id):
+ bundle = get_object_or_404(Bundle, id = bundle_id)
+ filter_settings = [(DelegateFilter, DelegateFilter.AnyDelegate)]
+
+ if request.method == 'POST' and request.POST.get('form') == 'bundle':
+ action = request.POST.get('action', '').lower()
+ if action == 'delete':
+ bundle.delete()
+ return HttpResponseRedirect(
+ django.core.urlresolvers.reverse(
+ 'patchwork.views.user.profile')
+ )
+ elif action == 'update':
+ form = BundleForm(request.POST, instance = bundle)
+ if form.is_valid():
+ form.save()
+ else:
+ form = BundleForm(instance = bundle)
+
+ context = generic_list(request, bundle.project,
+ 'patchwork.views.bundle.bundle',
+ view_args = {'bundle_id': bundle_id},
+ filter_settings = filter_settings,
+ patches = bundle.patches.all())
+
+ context['bundle'] = bundle
+ context['bundleform'] = form
+
+ return render_to_response('patchwork/bundle.html', context)
+
+@login_required
+def mbox(request, bundle_id):
+ bundle = get_object_or_404(Bundle, id = bundle_id)
+ response = HttpResponse(mimetype='text/plain')
+ response.write(bundle.mbox())
+ return response
+
+def public(request, username, bundlename):
+ user = get_object_or_404(User, username = username)
+ bundle = get_object_or_404(Bundle, name = bundlename, public = True)
+ filter_settings = [(DelegateFilter, DelegateFilter.AnyDelegate)]
+ context = generic_list(request, bundle.project,
+ 'patchwork.views.bundle.public',
+ view_args = {'username': username, 'bundlename': bundlename},
+ filter_settings = filter_settings,
+ patches = bundle.patches.all())
+
+ context.update({'bundle': bundle,
+ 'user': user});
+ return render_to_response('patchwork/bundle-public.html', context)
+
+@login_required
+def set_patches(request):
+ context = PatchworkRequestContext(request)
+
diff --git a/apps/patchwork/views/patch.py b/apps/patchwork/views/patch.py
new file mode 100644
index 0000000..d509e28
--- /dev/null
+++ b/apps/patchwork/views/patch.py
@@ -0,0 +1,180 @@
+# Patchwork - automated patch tracking system
+# Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
+#
+# This file is part of the Patchwork package.
+#
+# Patchwork is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Patchwork is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Patchwork; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+from patchwork.models import Patch, Project, Person, RegistrationRequest, Bundle
+from patchwork.filters import Filters
+from patchwork.forms import RegisterForm, LoginForm, PatchForm, MultiplePatchForm, CreateBundleForm
+from patchwork.utils import get_patch_ids, set_patches, Order
+from patchwork.requestcontext import PatchworkRequestContext
+from django.shortcuts import render_to_response, get_object_or_404
+from django.http import HttpResponse, HttpResponseRedirect, \
+ HttpResponseForbidden
+from django.contrib.auth.models import User
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth import authenticate, login
+import django.core.urlresolvers
+from patchwork.paginator import Paginator
+from patchwork.views import generic_list
+
+def patch(request, patch_id):
+ context = PatchworkRequestContext(request)
+ patch = get_object_or_404(Patch, id=patch_id)
+ context.project = patch.project
+ editable = patch.is_editable(request.user)
+ messages = []
+
+ form = None
+ createbundleform = None
+
+ if editable:
+ form = PatchForm(instance = patch)
+ if request.user.is_authenticated():
+ createbundleform = CreateBundleForm()
+
+ if request.method == 'POST':
+ action = request.POST.get('action', None)
+ if action:
+ action = action.lower()
+
+ if action == 'createbundle':
+ bundle = Bundle(owner = request.user, project = patch.project)
+ createbundleform = CreateBundleForm(instance = bundle,
+ data = request.POST)
+ if createbundleform.is_valid():
+ createbundleform.save()
+ bundle.patches.add(patch)
+ bundle.save()
+ createbundleform = CreateBundleForm()
+ context.add_message('Bundle %s created' % bundle.name)
+
+ elif action == 'addtobundle':
+ bundle = get_object_or_404(Bundle, id = \
+ request.POST.get('bundle_id'))
+ bundle.patches.add(patch)
+ bundle.save()
+ context.add_message('Patch added to bundle "%s"' % bundle.name)
+
+ # all other actions require edit privs
+ elif not editable:
+ return HttpResponseForbidden()
+
+ elif action is None:
+ form = PatchForm(data = request.POST, instance = patch)
+ if form.is_valid():
+ form.save()
+ context.add_message('Patch updated')
+
+ elif action == 'archive':
+ patch.archived = True
+ patch.save()
+ context.add_message('Patch archived')
+
+ elif action == 'unarchive':
+ patch.archived = False
+ patch.save()
+ context.add_message('Patch un-archived')
+
+ elif action == 'ack':
+ pass
+
+ elif action == 'delete':
+ patch.delete()
+
+
+ context['patch'] = patch
+ context['patchform'] = form
+ context['createbundleform'] = createbundleform
+ context['project'] = patch.project
+
+ return render_to_response('patchwork/patch.html', context)
+
+def content(request, patch_id):
+ patch = get_object_or_404(Patch, id=patch_id)
+ response = HttpResponse(mimetype="text/x-patch")
+ response.write(patch.content)
+ response['Content-Disposition'] = 'attachment; filename=' + \
+ patch.filename().replace(';', '').replace('\n', '')
+ return response
+
+def mbox(request, patch_id):
+ patch = get_object_or_404(Patch, id=patch_id)
+ response = HttpResponse(mimetype="text/plain")
+ response.write(patch.mbox().as_string(True))
+ response['Content-Disposition'] = 'attachment; filename=' + \
+ patch.filename().replace(';', '').replace('\n', '')
+ return response
+
+
+def list(request, project_id):
+ project = get_object_or_404(Project, linkname=project_id)
+ context = generic_list(request, project, 'patchwork.views.patch.list',
+ view_args = {'project_id': project.linkname})
+ return render_to_response('patchwork/list.html', context)
+
+ context = PatchworkRequestContext(request,
+ list_view = 'patchwork.views.patch.list',
+ list_view_params = {'project_id': project_id})
+ order = get_order(request)
+ project = get_object_or_404(Project, linkname=project_id)
+ context.project = project
+
+ form = None
+ errors = []
+
+ if request.method == 'POST':
+ action = request.POST.get('action', None)
+ if action:
+ action = action.lower()
+
+ # special case: the user may have hit enter in the 'create bundle'
+ # text field, so if non-empty, assume the create action:
+ if request.POST.get('bundle_name', False):
+ action = 'create'
+
+ ps = []
+ for patch_id in get_patch_ids(request.POST):
+ try:
+ patch = Patch.objects.get(id = patch_id)
+ except Patch.DoesNotExist:
+ pass
+ ps.append(patch)
+
+ (errors, form) = set_patches(request.user, action, request.POST, ps)
+ if errors:
+ context['errors'] = errors
+
+
+ elif request.user.is_authenticated() and \
+ project in request.user.get_profile().maintainer_projects.all():
+ form = MultiplePatchForm(project)
+
+ patches = Patch.objects.filter(project=project).order_by(order)
+ patches = context.filters.apply(patches)
+
+ paginator = Paginator(request, patches)
+
+ context.update({
+ 'page': paginator.current_page,
+ 'patchform': form,
+ 'project': project,
+ 'errors': errors,
+ })
+
+ return render_to_response('patchwork/list.html', context)
diff --git a/apps/patchwork/views/user.py b/apps/patchwork/views/user.py
new file mode 100644
index 0000000..223cfc6
--- /dev/null
+++ b/apps/patchwork/views/user.py
@@ -0,0 +1,201 @@
+# Patchwork - automated patch tracking system
+# Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
+#
+# This file is part of the Patchwork package.
+#
+# Patchwork is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Patchwork is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Patchwork; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+from django.contrib.auth.decorators import login_required
+from patchwork.requestcontext import PatchworkRequestContext
+from django.shortcuts import render_to_response, get_object_or_404
+from django.contrib import auth
+from django.http import HttpResponse, HttpResponseRedirect
+from patchwork.models import Project, Patch, Bundle, Person, \
+ RegistrationRequest, UserProfile, UserPersonConfirmation, State
+from patchwork.forms import RegisterForm, LoginForm, MultiplePatchForm, \
+ UserProfileForm, UserPersonLinkForm
+from patchwork.utils import Order, get_patch_ids, set_patches
+from patchwork.filters import DelegateFilter
+from patchwork.paginator import Paginator
+from patchwork.views import generic_list
+import django.core.urlresolvers
+
+def register(request):
+ context = PatchworkRequestContext(request)
+ template = 'patchwork/register.html'
+
+ if request.method != 'POST':
+ form = RegisterForm()
+ context['form'] = form
+ return render_to_response(template, context)
+
+ reg_req = RegistrationRequest()
+ form = RegisterForm(instance = reg_req, data = request.POST)
+
+ if form.is_valid():
+ form.save()
+ context['request'] = reg_req
+ else:
+ context['form'] = form
+
+ return render_to_response(template, context)
+
+def register_confirm(request, key):
+ context = PatchworkRequestContext(request)
+ req = get_object_or_404(RegistrationRequest, key = key)
+ req.create_user()
+ user = auth.authenticate(username = req.username, password = req.password)
+ auth.login(request, user)
+
+ return render_to_response('patchwork/register-confirm.html', context)
+
+def login(request):
+ context = PatchworkRequestContext(request)
+ template = 'patchwork/login.html'
+ error = None
+
+ if request.method == 'POST':
+ form = LoginForm(request.POST)
+ context['form'] = form
+
+ if not form.is_valid():
+ return render_to_response(template, context)
+
+ data = form.cleaned_data
+ user = auth.authenticate(username = data['username'],
+ password = data['password'])
+
+ if user is not None and user.is_active:
+ auth.login(request, user)
+ url = request.POST.get('next', None) or \
+ django.core.urlresolvers.reverse( \
+ 'patchwork.views.user.profile')
+ return HttpResponseRedirect(url)
+
+ context['error'] = 'Invalid username or password'
+
+ else:
+ context['form'] = LoginForm()
+
+ return render_to_response(template, context)
+
+def logout(request):
+ auth.logout(request)
+ return render_to_response('patchwork/logout.html')
+
+@login_required
+def profile(request):
+ context = PatchworkRequestContext(request)
+
+ if request.method == 'POST':
+ form = UserProfileForm(instance = request.user.get_profile(),
+ data = request.POST)
+ if form.is_valid():
+ form.save()
+ else:
+ form = UserProfileForm(instance = request.user.get_profile())
+
+ context.project = request.user.get_profile().primary_project
+ context['bundles'] = Bundle.objects.filter(owner = request.user)
+ context['profileform'] = form
+
+ people = Person.objects.filter(user = request.user)
+ context['linked_emails'] = people
+ context['linkform'] = UserPersonLinkForm()
+
+ return render_to_response('patchwork/profile.html', context)
+
+@login_required
+def link(request):
+ context = PatchworkRequestContext(request)
+
+ form = UserPersonLinkForm(request.POST)
+ if request.method == 'POST':
+ form = UserPersonLinkForm(request.POST)
+ if form.is_valid():
+ conf = UserPersonConfirmation(user = request.user,
+ email = form.cleaned_data['email'])
+ conf.save()
+ context['confirmation'] = conf
+
+ context['linkform'] = form
+
+ return render_to_response('patchwork/user-link.html', context)
+
+@login_required
+def link_confirm(request, key):
+ context = PatchworkRequestContext(request)
+ confirmation = get_object_or_404(UserPersonConfirmation, key = key)
+
+ errors = confirmation.confirm()
+ if errors:
+ context['errors'] = errors
+ else:
+ context['person'] = Person.objects.get(email = confirmation.email)
+
+ confirmation.delete()
+
+ return render_to_response('patchwork/user-link-confirm.html', context)
+
+@login_required
+def unlink(request, person_id):
+ context = PatchworkRequestContext(request)
+ person = get_object_or_404(Person, id = person_id)
+
+ if request.method == 'POST':
+ if person.email != request.user.email:
+ person.user = None
+ person.save()
+
+ url = django.core.urlresolvers.reverse('patchwork.views.user.profile')
+ return HttpResponseRedirect(url)
+
+
+@login_required
+def todo_lists(request):
+ todo_lists = []
+
+ for project in Project.objects.all():
+ patches = request.user.get_profile().todo_patches(project = project)
+ if not patches.count():
+ continue
+
+ todo_lists.append({'project': project, 'n_patches': patches.count()})
+
+ if len(todo_lists) == 1:
+ return todo_list(request, todo_lists[0]['project'].linkname)
+
+ context = PatchworkRequestContext(request)
+ context['todo_lists'] = todo_lists
+ context.project = request.user.get_profile().primary_project
+ return render_to_response('patchwork/todo-lists.html', context)
+
+@login_required
+def todo_list(request, project_id):
+ project = get_object_or_404(Project, linkname = project_id)
+ patches = request.user.get_profile().todo_patches(project = project)
+ filter_settings = [(DelegateFilter,
+ {'delegate': request.user})]
+
+ context = generic_list(request, project,
+ 'patchwork.views.user.todo_list',
+ view_args = {'project_id': project.linkname},
+ filter_settings = filter_settings,
+ patches = patches)
+
+ context['action_required_states'] = \
+ State.objects.filter(action_required = True).all()
+ return render_to_response('patchwork/todo-list.html', context)