patch.py 6.09 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

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

31

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

    form = None
    createbundleform = None

40
41
    current_revision = None

42
43
44
45
46
47
48
49
50
    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")
51

Jeremy Kerr's avatar
Jeremy Kerr committed
52
    if editable:
53
        form = PatchForm(instance=patch)
54
    if request.user.is_authenticated:
Jeremy Kerr's avatar
Jeremy Kerr committed
55
56
57
58
59
60
61
62
        createbundleform = CreateBundleForm()

    if request.method == 'POST':
        action = request.POST.get('action', None)
        if action:
            action = action.lower()

        if action == 'createbundle':
63
64
65
            bundle = Bundle(owner=request.user, project=patch.project)
            createbundleform = CreateBundleForm(instance=bundle,
                                                data=request.POST)
Jeremy Kerr's avatar
Jeremy Kerr committed
66
67
            if createbundleform.is_valid():
                createbundleform.save()
Jeremy Kerr's avatar
Jeremy Kerr committed
68
                bundle.append_patch(patch)
Jeremy Kerr's avatar
Jeremy Kerr committed
69
70
                bundle.save()
                createbundleform = CreateBundleForm()
71
                messages += ['Bundle %s created' % bundle.name]
Jeremy Kerr's avatar
Jeremy Kerr committed
72
73

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

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

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

94
95
96
97
98
99
100
101
102
    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)

103
104
105
106
107
108
        try:
            current_patch_index = all_patches.index(patch)
            current_patch_number = current_patch_index + 1
        except ValueError:
            raise Http404("Patch {} does not belong to {}v{}"
                          .format(patch_id, series, rev))
109
110
111
112
113
114

        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]

115
    context = {
116
        'seriesrevisions': group(patch.all_revisions(), lambda r: r.series),
117
        'patch': patch,
118
119
120
121
122
        'current_revision': current_revision,
        'prev_patch': prev_patch,
        'next_patch': next_patch,
        'patch_count': patch_count,
        'current_patch_number': current_patch_number,
123
124
125
126
127
128
129
        '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
130

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

133

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

142

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

163

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


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