diff options
Diffstat (limited to 'apps/patchwork/views')
-rw-r--r-- | apps/patchwork/views/__init__.py | 90 | ||||
-rw-r--r-- | apps/patchwork/views/base.py | 66 | ||||
-rw-r--r-- | apps/patchwork/views/bundle.py | 158 | ||||
-rw-r--r-- | apps/patchwork/views/patch.py | 180 | ||||
-rw-r--r-- | apps/patchwork/views/user.py | 201 |
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) |