patch.py 6.12 KB
Newer Older
Jeremy Kerr's avatar
Jeremy Kerr committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# 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

20
from __future__ import absolute_import
Jeremy Kerr's avatar
Jeremy Kerr committed
21

22
from django.http import HttpResponse, HttpResponseForbidden, Http404
23
from django.shortcuts import get_object_or_404, redirect, render
Stephen Finucane's avatar
Stephen Finucane committed
24
from django.utils import six
Stephen Finucane's avatar
Stephen Finucane committed
25

26
from patchwork.utils import group
Stephen Finucane's avatar
Stephen Finucane committed
27
from patchwork.forms import PatchForm, CreateBundleForm
28
from patchwork.models import Patch, Project, Bundle, TestResult, SeriesRevision
29
from patchwork.views import generic_list, patch_to_mbox
30
from patchwork.permissions import Can
Jeremy Kerr's avatar
Jeremy Kerr committed
31

32

Jeremy Kerr's avatar
Jeremy Kerr committed
33 34
def patch(request, patch_id):
    patch = get_object_or_404(Patch, id=patch_id)
35
    editable = Can(request.user).edit(patch)
36
    messages = []
Jeremy Kerr's avatar
Jeremy Kerr committed
37 38 39 40

    form = None
    createbundleform = None

41 42 43 44 45 46 47 48 49 50 51 52 53
    current_revision = None

    if request.method == 'GET':
        series = request.GET.get('series', None)
        rev = request.GET.get('rev', None)
        if series and rev:
            try:
                current_revision = SeriesRevision.objects.get(
                        series_id=int(series),
                        version=int(rev))
            except Exception:
                raise Http404("Wrong series/revision")

Jeremy Kerr's avatar
Jeremy Kerr committed
54
    if editable:
55
        form = PatchForm(instance=patch)
Jeremy Kerr's avatar
Jeremy Kerr committed
56 57 58 59 60 61 62 63 64
    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':
65 66 67
            bundle = Bundle(owner=request.user, project=patch.project)
            createbundleform = CreateBundleForm(instance=bundle,
                                                data=request.POST)
Jeremy Kerr's avatar
Jeremy Kerr committed
68 69
            if createbundleform.is_valid():
                createbundleform.save()
Jeremy Kerr's avatar
Jeremy Kerr committed
70
                bundle.append_patch(patch)
Jeremy Kerr's avatar
Jeremy Kerr committed
71 72
                bundle.save()
                createbundleform = CreateBundleForm()
73
                messages += ['Bundle %s created' % bundle.name]
Jeremy Kerr's avatar
Jeremy Kerr committed
74 75

        elif action == 'addtobundle':
76 77
            bundle = get_object_or_404(
                Bundle, id=request.POST.get('bundle_id'))
Jeremy Kerr's avatar
Jeremy Kerr committed
78 79 80
            try:
                bundle.append_patch(patch)
                bundle.save()
81
                messages += ['Patch added to bundle "%s"' % bundle.name]
Stephen Finucane's avatar
Stephen Finucane committed
82
            except Exception as ex:
83 84
                messages += ["Couldn't add patch '%s' to bundle %s: %s"
                             % (patch.name, bundle.name, ex.message)]
Jeremy Kerr's avatar
Jeremy Kerr committed
85

86
        # all other actions require edit privs
Jeremy Kerr's avatar
Jeremy Kerr committed
87 88 89 90
        elif not editable:
            return HttpResponseForbidden()

        elif action is None:
91
            form = PatchForm(data=request.POST, instance=patch)
Jeremy Kerr's avatar
Jeremy Kerr committed
92 93
            if form.is_valid():
                form.save()
94
                messages += ['Patch updated']
Jeremy Kerr's avatar
Jeremy Kerr committed
95

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
    prev_patch = None
    next_patch = None
    patch_count = 0
    current_patch_number = 0

    if current_revision:
        all_patches = [x for x in current_revision.patches.all()]
        patch_count = len(all_patches)

        current_patch_index = all_patches.index(patch)
        current_patch_number = current_patch_index + 1

        if (current_patch_index + 1) < patch_count:
            next_patch = all_patches[current_patch_index + 1]
        if current_patch_index > 0:
            prev_patch = all_patches[current_patch_index - 1]

113
    context = {
114
        'seriesrevisions': group(patch.all_revisions(), lambda r: r.series),
115
        'patch': patch,
116 117 118 119 120
        'current_revision': current_revision,
        'prev_patch': prev_patch,
        'next_patch': next_patch,
        'patch_count': patch_count,
        'current_patch_number': current_patch_number,
121 122 123 124 125 126 127
        'patchform': form,
        'createbundleform': createbundleform,
        'project': patch.project,
        'messages': messages,
        'test_results': TestResult.objects
                        .filter(revision=None, patch=patch)
                        .order_by('test__name').select_related('test')}
Jeremy Kerr's avatar
Jeremy Kerr committed
128

129
    return render(request, 'patchwork/patch.html', context)
Jeremy Kerr's avatar
Jeremy Kerr committed
130

131

Jeremy Kerr's avatar
Jeremy Kerr committed
132 133
def content(request, patch_id):
    patch = get_object_or_404(Patch, id=patch_id)
134
    response = HttpResponse(content_type="text/x-patch")
Jeremy Kerr's avatar
Jeremy Kerr committed
135 136 137 138 139
    response.write(patch.content)
    response['Content-Disposition'] = 'attachment; filename=' + \
        patch.filename().replace(';', '').replace('\n', '')
    return response

140

Jeremy Kerr's avatar
Jeremy Kerr committed
141 142
def mbox(request, patch_id):
    patch = get_object_or_404(Patch, id=patch_id)
143 144 145 146
    options = {
        'patch-link': request.GET.get('link', None),
        'request': request,
    }
147
    response = HttpResponse(content_type="text/plain")
Stephen Finucane's avatar
Stephen Finucane committed
148 149
    # NOTE(stephenfin) http://stackoverflow.com/a/28584090/613428
    if six.PY3:
150
        response.write(patch_to_mbox(patch, options).as_bytes(True).decode())
Stephen Finucane's avatar
Stephen Finucane committed
151
    else:
152
        response.write(patch_to_mbox(patch, options).as_string(True))
Jeremy Kerr's avatar
Jeremy Kerr committed
153 154 155 156 157 158 159
    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)
Arkadiusz Hiler's avatar
Arkadiusz Hiler committed
160
    context = generic_list(request, project, 'patch_list',
161
                           view_args={'project_id': project.linkname})
162
    return render(request, 'patchwork/list.html', context)
163

164

165
def _get_patch_or_404(msgid):
166 167 168 169 170 171
    patch = Patch.objects.filter(msgid='<' + msgid + '>').first()
    if patch is None:
        raise Http404("Patch not found")
    return patch


172
def msgid(request, msgid):
173
    patch = _get_patch_or_404(msgid)
174
    return redirect(patch)