1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
from django.shortcuts import get_object_or_404
from django.http import HttpResponse, Http404, HttpResponseForbidden
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
from functools import wraps
from django.utils.decorators import available_attrs
from django.db import connection
import datetime
import json
from models import CommitFest, Patch, PatchBuildStatus, BuildProvider
def api_authenticate(view_func):
def _wrapped_view(request, *args, **kwargs):
if not request.META['REMOTE_ADDR'] in settings.API_AUTH:
return HttpResponseForbidden('Access Denied')
if not request.META.get('HTTP_X_API_AUTH', '') == settings.API_AUTH[request.META['REMOTE_ADDR']]:
return HttpResponseForbidden('Access Denied')
return view_func(request, *args, **kwargs)
return wraps(view_func, assigned=available_attrs(view_func))(_wrapped_view)
@api_authenticate
def active_commitfests(request):
cfs = list(CommitFest.objects.filter(status=CommitFest.STATUS_INPROGRESS))
if not cfs:
cfs = CommitFest.objects.filter(status=CommitFest.STATUS_OPEN).order_by('-id')[:1]
res = [
{'id': c.id, 'name': c.name, 'status': c.statusstring, 'numstatus': c.status} for c in cfs
]
return HttpResponse(json.dumps(res),
content_type='application/json')
@api_authenticate
def commitfest(request, cfid):
cf = get_object_or_404(CommitFest, pk=cfid)
whereclauses = []
params = { 'cid': cf.id }
if 'since' in request.GET:
whereclauses.append("latestmessage > %(since)s")
params['since'] = request.GET['since']
if whereclauses:
wherestring = 'AND ({0})'.format(
' AND '.join(whereclauses)
)
else:
wherestring = ''
curs = connection.cursor()
curs.execute("""SELECT p.id, p.name, poc.status,
json_agg(json_build_object(
'msgid', mt.messageid,
'first', mt.firstmessage,
'latest', mt.latestmessage,
'attachments', attachments
)) AS threads
FROM commitfest_patch p
INNER JOIN commitfest_patchoncommitfest poc ON poc.patch_id=p.id
LEFT JOIN (
SELECT mtp.patch_id, t.messageid, t.firstmessage, t.latestmessage,
json_agg(json_build_object('messageid', mta.messageid, 'attachmentid', mta.attachmentid, 'filename', mta.filename, 'time', mta.date)) AS attachments
FROM commitfest_mailthread_patches mtp
INNER JOIN commitfest_mailthread t ON t.id=mtp.mailthread_id
LEFT JOIN commitfest_mailthreadattachment mta ON mta.mailthread_id=t.id
GROUP BY mtp.patch_id, t.id
) AS mt ON mt.patch_id=p.id
WHERE poc.commitfest_id=%(cid)s {0}
GROUP BY p.id, poc.id""".format(wherestring), params)
res = {
'patches': [dict(zip([col[0] for col in curs.description], row)) for row in curs.fetchall()],
}
return HttpResponse(json.dumps(res),
content_type='application/json')
@csrf_exempt
@api_authenticate
def build_result(request, cfid, patchid):
if request.method != 'POST':
return HttpResponse('Invalid method', status=405)
if request.META['CONTENT_TYPE'] != 'application/json':
return HttpResponse("Only JSON accepted", status=415)
try:
obj = json.loads(request.body)
except ValueError:
return HttpResponse("Invalid data format", status=415)
commitfest = get_object_or_404(CommitFest, pk=cfid)
patch = get_object_or_404(Patch, pk=patchid)
# Mandatory fields
try:
provider = BuildProvider.objects.get(urlname=obj['provider'])
messageid = obj['messageid']
status = obj['status']
statustime = obj['timestamp']
except BuildProvider.DoesNotExist:
return HttpResponse("Invalid build provider", status=422)
except KeyError, e:
return HttpResponse("Mandatory parameter {0} missing".format(e.args[0]), status=400)
if not status in PatchBuildStatus._STATUS_MAP:
return HttpResponse("Invalid build status {0}".format(status), status=422)
try:
statustime = datetime.datetime.strptime(statustime, '%Y-%m-%dT%H:%M:%S.%fZ')
except ValueError:
return HttpResponse("Invalid timestamp {0}".format(statustime), status=422)
# Optional parameters
url = obj.get('url', '')
commitid = obj.get('commit', '')
(buildstatus, created) = PatchBuildStatus.objects.get_or_create(commitfest=commitfest,
patch=patch,
buildprovider=provider,
status_timestamp=statustime,
defaults={
'buildmessageid': messageid,
'buildstatus': PatchBuildStatus._STATUS_MAP[status],
'status_url': url,
'master_commit_id': commitid,
},
)
if not created:
if buildstatus.buildmessageid == messageid and \
buildstatus.buildstatus == PatchBuildStatus._STATUS_MAP[status] and \
buildstatus.status_url == url and \
buildstatus.master_commit_id == commitid:
return HttpResponse("Build status already stored", status=200)
return HttpResponse("Conflicting build status already stored", status=409)
# That's it!
return HttpResponse("Stored", status=201)
|