Merge lp:~salgado/offspring/make-piston-handlers-privacy-aware into lp:offspring
- make-piston-handlers-privacy-aware
- Merge into trunk
Proposed by
Guilherme Salgado
Status: | Superseded |
---|---|
Proposed branch: | lp:~salgado/offspring/make-piston-handlers-privacy-aware |
Merge into: | lp:offspring |
Prerequisite: | lp:~salgado/offspring/acl-editor |
Diff against target: |
669 lines (+409/-48) 11 files modified
config/offspring.cfg (+2/-2) lib/offspring/web/queuemanager/handlers.py (+23/-15) lib/offspring/web/queuemanager/models.py (+4/-2) lib/offspring/web/queuemanager/tests/__init__.py (+1/-0) lib/offspring/web/queuemanager/tests/factory.py (+3/-2) lib/offspring/web/queuemanager/tests/helpers.py (+14/-0) lib/offspring/web/queuemanager/tests/test_handlers.py (+300/-0) lib/offspring/web/queuemanager/tests/test_views.py (+49/-16) lib/offspring/web/queuemanager/views.py (+13/-5) lib/offspring/web/settings.py (+0/-3) lib/offspring/web/settings_production.py (+0/-3) |
To merge this branch: | bzr merge lp:~salgado/offspring/make-piston-handlers-privacy-aware |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Offspring Committers | Pending | ||
Review via email: mp+84279@code.launchpad.net |
Commit message
Description of the change
Update the piston handlers to include private objects the user is allowed to see.
To post a comment you must log in.
- 105. By Guilherme Salgado
-
Plenty of docstrings for tests
- 106. By Guilherme Salgado
-
A few changes suggested by Kevin
- 107. By Guilherme Salgado
-
merge trunk
- 108. By Guilherme Salgado
-
A few more changes suggested by Kevin
- 109. By Guilherme Salgado
-
Remove base_dir from config/
offspring. cfg or else the tree root will not be used - 110. By Guilherme Salgado
-
Fix one last thing Keving mentioned
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'config/offspring.cfg' |
2 | --- config/offspring.cfg 2011-11-30 14:15:52 +0000 |
3 | +++ config/offspring.cfg 2011-12-02 15:32:33 +0000 |
4 | @@ -159,8 +159,8 @@ |
5 | |
6 | [publisher] |
7 | db: postgres://offspring:temp1234@localhost/offspring |
8 | -development_pool: /srv/builds/ |
9 | -production_pool: /srv/partners/ |
10 | +development_pool: %(base_dir)s/builds/ |
11 | +production_pool: %(base_dir)s/partners/ |
12 | signer_directory: |
13 | signer_files: |
14 | signer_results: |
15 | |
16 | === modified file 'lib/offspring/web/queuemanager/handlers.py' |
17 | --- lib/offspring/web/queuemanager/handlers.py 2011-08-13 07:24:06 +0000 |
18 | +++ lib/offspring/web/queuemanager/handlers.py 2011-12-02 15:32:33 +0000 |
19 | @@ -43,9 +43,11 @@ |
20 | allowed_methods = ('GET') |
21 | |
22 | def read(self, request, projectName, buildName): |
23 | + projects = Project.all_objects.accessible_by_user(request.user) |
24 | try: |
25 | - project = Project.objects.get(pk=projectName) |
26 | - build = BuildResult.objects.get(project=project, name=buildName) |
27 | + project = projects.get(pk=projectName) |
28 | + build = BuildResult.all_objects.accessible_by_user( |
29 | + request.user).get(project=project, name=buildName) |
30 | except: |
31 | return rc.NOT_FOUND |
32 | manifestPath = glob.glob(build.result_directory + '/images/*/*.manifest')[0] |
33 | @@ -56,14 +58,17 @@ |
34 | allowed_methods = ('GET') |
35 | |
36 | def read(self, request, projectName, buildName): |
37 | + projects = Project.all_objects.accessible_by_user(request.user) |
38 | + builds = BuildResult.all_objects.accessible_by_user(request.user) |
39 | try: |
40 | - project = Project.objects.get(pk=projectName) |
41 | - base_build = BuildResult.objects.get(project=project, name=buildName) |
42 | + project = projects.get(pk=projectName) |
43 | + base_build = builds.get(project=project, name=buildName) |
44 | except: |
45 | return rc.NOT_FOUND |
46 | if request.GET.has_key('build'): |
47 | try: |
48 | - target_build = BuildResult.objects.get(project=project, name=request.GET['build']) |
49 | + target_build = builds.get( |
50 | + project=project, name=request.GET['build']) |
51 | except: |
52 | return rc.NOT_FOUND |
53 | else: |
54 | @@ -81,6 +86,7 @@ |
55 | return output |
56 | |
57 | |
58 | +# TODO: Must be made privacy-aware. |
59 | class ProjectNotificationSubscriptionHandler(BaseHandler): |
60 | allowed_methods = ('GET', 'POST', 'DELETE') |
61 | model = ProjectNotificationSubscription |
62 | @@ -138,7 +144,7 @@ |
63 | 'reason', 'result', 'notes', 'is_released') |
64 | |
65 | def read(self, request, projectName=None, buildName=None, builderName=None): |
66 | - results = BuildResult.objects.all() |
67 | + results = BuildResult.all_objects.accessible_by_user(request.user) |
68 | if projectName is not None: |
69 | results = results.filter(project__name=projectName) |
70 | if buildName is not None: |
71 | @@ -155,10 +161,10 @@ |
72 | |
73 | def read(self, request, projectName=None, request_id=None): |
74 | try: |
75 | + requests = BuildRequest.all_objects.accessible_by_user( |
76 | + request.user) |
77 | if projectName is not None: |
78 | - requests = BuildRequest.objects.filter(project__name=projectName) |
79 | - else: |
80 | - requests = BuildRequest.objects |
81 | + requests = requests.filter(project__name=projectName) |
82 | except: |
83 | return rc.NOT_FOUND |
84 | if request_id is not None: |
85 | @@ -170,12 +176,12 @@ |
86 | def delete(self, request, projectName=None, request_id=None): |
87 | if request.user.has_perm("queuemanager.can_build"): |
88 | try: |
89 | + requests = BuildRequest.all_objects.accessible_by_user( |
90 | + request.user) |
91 | if projectName is not None: |
92 | - requests = BuildRequest.objects.filter(project__name=projectName) |
93 | - else: |
94 | - requests = BuildRequest.objects |
95 | + requests = requests.filter(project__name=projectName) |
96 | except: |
97 | - return RC.NOT_FOUND |
98 | + return rc.NOT_FOUND |
99 | if request_id is not None: |
100 | try: |
101 | requests.get(pk=request_id).delete() |
102 | @@ -195,7 +201,8 @@ |
103 | def create(self, request, projectName): |
104 | if request.user.has_perm("queuemanager.can_build"): |
105 | try: |
106 | - p = Project.objects.get(pk=projectName) |
107 | + p = Project.all_objects.accessible_by_user(request.user).get( |
108 | + pk=projectName) |
109 | if request.POST.has_key('build_reason'): |
110 | request = BuildRequest.queue_build(p, request.user, reason=request.POST['build_reason'], scoreBonus=25) |
111 | else: |
112 | @@ -217,8 +224,9 @@ |
113 | 'created_at', 'published_at', 'status', 'checklist_url', 'notes') |
114 | |
115 | def read(self, request, projectName): |
116 | + objects = Release.all_objects.accessible_by_user(request.user) |
117 | try: |
118 | - releases = Release.objects.filter(build__project__name=projectName) |
119 | + releases = objects.filter(build__project__name=projectName) |
120 | except: |
121 | return rc.NOT_FOUND |
122 | return releases |
123 | |
124 | === modified file 'lib/offspring/web/queuemanager/models.py' |
125 | --- lib/offspring/web/queuemanager/models.py 2011-11-30 14:15:52 +0000 |
126 | +++ lib/offspring/web/queuemanager/models.py 2011-12-02 15:32:33 +0000 |
127 | @@ -12,7 +12,6 @@ |
128 | ) |
129 | import math |
130 | |
131 | -from django.conf import settings |
132 | from django.contrib.auth.models import AnonymousUser, User |
133 | from django.db import ( |
134 | connection, |
135 | @@ -23,9 +22,12 @@ |
136 | AccessGroup, |
137 | AccessGroupMixin, |
138 | AccessManager) |
139 | +from offspring.config import get_configuration |
140 | from offspring.enums import ProjectBuildStates |
141 | |
142 | |
143 | +config = get_configuration() |
144 | + |
145 | ARCH_CHOICES = ( |
146 | (u'i386', u'i386'), |
147 | (u'amd64', u'amd64'), |
148 | @@ -412,7 +414,7 @@ |
149 | def result_directory(self): |
150 | if self.name: |
151 | try: |
152 | - base_dir = getattr(settings, 'BUILDRESULTS_DIRECTORY', '/srv/builds/') |
153 | + base_dir = config.get('builder', 'result_dir') |
154 | buildDate, buildId = self.name.rsplit('-', 1) |
155 | except: |
156 | return None |
157 | |
158 | === modified file 'lib/offspring/web/queuemanager/tests/__init__.py' |
159 | --- lib/offspring/web/queuemanager/tests/__init__.py 2011-12-02 15:32:33 +0000 |
160 | +++ lib/offspring/web/queuemanager/tests/__init__.py 2011-12-02 15:32:33 +0000 |
161 | @@ -1,2 +1,3 @@ |
162 | +from .test_handlers import * |
163 | from offspring.web.queuemanager.tests.test_models import * |
164 | from offspring.web.queuemanager.tests.test_views import * |
165 | |
166 | === modified file 'lib/offspring/web/queuemanager/tests/factory.py' |
167 | --- lib/offspring/web/queuemanager/tests/factory.py 2011-12-02 15:32:33 +0000 |
168 | +++ lib/offspring/web/queuemanager/tests/factory.py 2011-12-02 15:32:33 +0000 |
169 | @@ -73,7 +73,8 @@ |
170 | title = self.get_unique_string() |
171 | return ProjectGroup.objects.create(name=name, title=title) |
172 | |
173 | - def make_build_result(self, project=None, name=None, result=None): |
174 | + def make_build_result(self, project=None, name=None, result=None, |
175 | + builder=None): |
176 | """ |
177 | Create a BuildResult with the given project or a newly created one if |
178 | none is given. |
179 | @@ -83,7 +84,7 @@ |
180 | if project is None: |
181 | project = self.make_project() |
182 | return BuildResult.objects.create( |
183 | - project=project, name=name, result=result) |
184 | + project=project, name=name, result=result, builder=builder) |
185 | |
186 | def make_release(self, build=None, name=None, creator=None): |
187 | """ |
188 | |
189 | === added file 'lib/offspring/web/queuemanager/tests/helpers.py' |
190 | --- lib/offspring/web/queuemanager/tests/helpers.py 1970-01-01 00:00:00 +0000 |
191 | +++ lib/offspring/web/queuemanager/tests/helpers.py 2011-12-02 15:32:33 +0000 |
192 | @@ -0,0 +1,14 @@ |
193 | +from django.contrib.auth.models import ( |
194 | + Group, |
195 | + Permission, |
196 | + ) |
197 | + |
198 | + |
199 | +def grant_permission_to_user(user, permission): |
200 | + group = Group(name=user.username) |
201 | + group.save() |
202 | + group.permissions.add(Permission.objects.get(codename=permission)) |
203 | + group.save() |
204 | + user.groups.add(group) |
205 | + user.save() |
206 | + return user |
207 | |
208 | === added file 'lib/offspring/web/queuemanager/tests/test_handlers.py' |
209 | --- lib/offspring/web/queuemanager/tests/test_handlers.py 1970-01-01 00:00:00 +0000 |
210 | +++ lib/offspring/web/queuemanager/tests/test_handlers.py 2011-12-02 15:32:33 +0000 |
211 | @@ -0,0 +1,300 @@ |
212 | +import errno |
213 | +import os |
214 | + |
215 | +from django.contrib.auth import authenticate, login |
216 | +from django.http import HttpRequest, HttpResponse |
217 | +from django.test import TestCase |
218 | +from django.contrib.sessions.middleware import SessionMiddleware |
219 | + |
220 | +from piston.utils import rc |
221 | + |
222 | +from offspring.web.queuemanager.models import BuildRequest |
223 | +from offspring.web.queuemanager.handlers import ( |
224 | + BuildManifestComparisonHandler, |
225 | + BuildManifestHandler, |
226 | + BuildRequestHandler, |
227 | + BuildResultHandler, |
228 | + ReleaseHandler, |
229 | + ) |
230 | +from offspring.web.queuemanager.tests.factory import factory |
231 | +from offspring.web.queuemanager.tests.helpers import grant_permission_to_user |
232 | + |
233 | + |
234 | +class BaseHandlerTestCase(TestCase): |
235 | + |
236 | + def setUp(self): |
237 | + super(BaseHandlerTestCase, self).setUp() |
238 | + self.request = HttpRequest() |
239 | + self.request.method = 'GET' |
240 | + # Set request.user and process the request manually using |
241 | + # SessionMiddleware so that we can use login(request, user) in tests. |
242 | + self.request.user = None |
243 | + SessionMiddleware().process_request(self.request) |
244 | + |
245 | + def _login(self, user): |
246 | + user = authenticate(username=user.username, password=user.username) |
247 | + login(self.request, user) |
248 | + return user |
249 | + |
250 | + |
251 | +class BuildResultHandlerTests(BaseHandlerTestCase): |
252 | + |
253 | + def test_builds_for_inexistent_project(self): |
254 | + results = BuildResultHandler().read( |
255 | + self.request, projectName='not-existent') |
256 | + self.assertEqual(0, results.count()) |
257 | + |
258 | + def test_inexistent_build(self): |
259 | + results = BuildResultHandler().read( |
260 | + self.request, buildName='not-existent') |
261 | + self.assertEqual(0, results.count()) |
262 | + |
263 | + def test_public_project_builds(self): |
264 | + # The builds of public projects are visible to anyone. |
265 | + build = make_build(is_private=False) |
266 | + self.assertBuildIsVisibleToUser(build, factory.make_user()) |
267 | + |
268 | + def test_private_project_build_is_visible_to_project_owner(self): |
269 | + build = make_build(is_private=True) |
270 | + self.assertBuildIsVisibleToUser(build, build.project.owner) |
271 | + |
272 | + def test_private_project_builds_invisible_to_user(self): |
273 | + # If the user has no rights to see a given project, they'll get an |
274 | + # empty list of builds, just like if the project didn't exist. |
275 | + build = make_build(is_private=True) |
276 | + self.assertBuildIsNotVisibleToUser(build, factory.make_user()) |
277 | + |
278 | + def assertBuildIsVisibleToUser(self, build, user): |
279 | + """Assert that the given build is visible to the given user.""" |
280 | + user = self._login(user) |
281 | + handler = BuildResultHandler() |
282 | + |
283 | + # It is visible when looking at all project builds... |
284 | + results = handler.read(self.request, projectName=build.project.name) |
285 | + self.assertEqual(1, results.count()) |
286 | + self.assertEqual([build], list(results)) |
287 | + |
288 | + # when looking at one specific build ... |
289 | + results = handler.read(self.request, buildName=build.name) |
290 | + self.assertEqual(1, results.count()) |
291 | + self.assertEqual([build], list(results)) |
292 | + |
293 | + # and when looking at all builds of a builder. |
294 | + results = handler.read(self.request, builderName=build.builder.name) |
295 | + self.assertEqual(1, results.count()) |
296 | + self.assertEqual([build], list(results)) |
297 | + |
298 | + def assertBuildIsNotVisibleToUser(self, build, user): |
299 | + """Assert that the given build is not visible to the given user.""" |
300 | + user = self._login(user) |
301 | + handler = BuildResultHandler() |
302 | + |
303 | + # It is *not* visible when looking at all project builds... |
304 | + results = handler.read(self.request, projectName=build.project.name) |
305 | + self.assertEqual(0, results.count()) |
306 | + |
307 | + # when looking at one specific build ... |
308 | + results = handler.read(self.request, buildName=build.name) |
309 | + self.assertEqual(0, results.count()) |
310 | + |
311 | + # and when looking at all builds of a builder. |
312 | + results = handler.read(self.request, builderName=build.builder.name) |
313 | + self.assertEqual(0, results.count()) |
314 | + |
315 | + |
316 | +class BuildRequestHandlerTests(BaseHandlerTestCase): |
317 | + |
318 | + def test_public_build_request_is_visible_to_anyone(self): |
319 | + job = factory.make_build_request( |
320 | + project=factory.make_project(is_private=False)) |
321 | + results = BuildRequestHandler().read( |
322 | + self.request, projectName=job.project.name, request_id=job.id) |
323 | + self.assertEqual(job, results) |
324 | + |
325 | + def test_private_build_request_is_visible_to_owner(self): |
326 | + job = factory.make_build_request( |
327 | + project=factory.make_project(is_private=True)) |
328 | + self._login(job.project.owner) |
329 | + results = BuildRequestHandler().read( |
330 | + self.request, projectName=job.project.name, request_id=job.id) |
331 | + self.assertEqual(job, results) |
332 | + |
333 | + def test_private_build_request_is_not_visible_to_others(self): |
334 | + job = factory.make_build_request( |
335 | + project=factory.make_project(is_private=True)) |
336 | + self._login(factory.make_user()) |
337 | + self.assertRaises( |
338 | + BuildRequest.DoesNotExist, |
339 | + BuildRequestHandler().read, |
340 | + self.request, projectName=job.project.name, request_id=job.id) |
341 | + |
342 | + def test_new_build_request_on_public_project(self): |
343 | + project = factory.make_project(is_private=False) |
344 | + self.assertCreateReturnCode( |
345 | + project, factory.make_user(), rc.CREATED.status_code) |
346 | + |
347 | + def test_owner_requests_new_build_on_private_project(self): |
348 | + project = factory.make_project(is_private=True) |
349 | + self.assertCreateReturnCode( |
350 | + project, project.owner, rc.CREATED.status_code) |
351 | + |
352 | + def test_other_user_requests_new_build_on_private_project(self): |
353 | + project = factory.make_project(is_private=True) |
354 | + self.assertCreateReturnCode( |
355 | + project, factory.make_user(), rc.BAD_REQUEST.status_code) |
356 | + |
357 | + def test_delete_build_request_on_public_project(self): |
358 | + job = factory.make_build_request( |
359 | + project=factory.make_project(is_private=False)) |
360 | + self.assertDeleteReturnCode( |
361 | + job, factory.make_user(), rc.DELETED.status_code) |
362 | + |
363 | + def test_owner_deletes_build_request_on_private_project(self): |
364 | + job = factory.make_build_request( |
365 | + project=factory.make_project(is_private=True)) |
366 | + self.assertDeleteReturnCode( |
367 | + job, job.project.owner, rc.DELETED.status_code) |
368 | + |
369 | + def test_other_user_deletes_build_request_on_private_project(self): |
370 | + job = factory.make_build_request( |
371 | + project=factory.make_project(is_private=True)) |
372 | + self.assertDeleteReturnCode( |
373 | + job, factory.make_user(), rc.NOT_FOUND.status_code) |
374 | + |
375 | + def assertCreateReturnCode(self, project, user, return_code): |
376 | + """Assert that BuildRequestHandler.create() returns the given code. |
377 | + |
378 | + Also grant the given user the 'can_build' permission and logs it in. |
379 | + """ |
380 | + grant_permission_to_user(user, 'can_build') |
381 | + self._login(user) |
382 | + result = BuildRequestHandler().create( |
383 | + self.request, projectName=project.name) |
384 | + self.assertEqual(return_code, result.status_code) |
385 | + |
386 | + def assertDeleteReturnCode(self, job, user, return_code): |
387 | + """Assert that BuildRequestHandler.delete() returns the given code. |
388 | + |
389 | + Also grant the given user the 'can_build' permission and logs it in. |
390 | + """ |
391 | + grant_permission_to_user(user, 'can_build') |
392 | + self._login(user) |
393 | + result = BuildRequestHandler().delete( |
394 | + self.request, projectName=job.project.name, request_id=job.id) |
395 | + self.assertEqual(return_code, result.status_code) |
396 | + |
397 | + |
398 | +class ReleaseHandlerTests(BaseHandlerTestCase): |
399 | + |
400 | + def test_public_project_release(self): |
401 | + release = factory.make_release(make_build(is_private=False)) |
402 | + results = ReleaseHandler().read( |
403 | + self.request, projectName=release.build.project.name) |
404 | + self.assertEqual(1, results.count()) |
405 | + self.assertEqual([release], list(results)) |
406 | + |
407 | + def test_private_project_release_is_visible_to_owner(self): |
408 | + release = factory.make_release(make_build(is_private=True)) |
409 | + user = self._login(release.build.project.owner) |
410 | + results = ReleaseHandler().read( |
411 | + self.request, projectName=release.build.project.name) |
412 | + self.assertEqual(1, results.count()) |
413 | + self.assertEqual([release], list(results)) |
414 | + |
415 | + def test_private_project_release_is_not_visible_to_others(self): |
416 | + release = factory.make_release(make_build(is_private=True)) |
417 | + user = self._login(factory.make_user()) |
418 | + results = ReleaseHandler().read( |
419 | + self.request, projectName=release.build.project.name) |
420 | + self.assertEqual(0, results.count()) |
421 | + |
422 | + |
423 | +class BuildManifestHandlerTests(BaseHandlerTestCase): |
424 | + |
425 | + def test_public_project_build_manifest(self): |
426 | + build = make_build(is_private=False) |
427 | + make_build_manifest_file(build) |
428 | + results = BuildManifestHandler().read( |
429 | + self.request, build.project.name, build.name) |
430 | + self.assertEqual([{'package': 'foo', 'version': '1.2'}], results) |
431 | + |
432 | + def test_private_project_build_manifest_is_visible_to_owner(self): |
433 | + build = make_build(is_private=True) |
434 | + make_build_manifest_file(build) |
435 | + user = self._login(build.project.owner) |
436 | + results = BuildManifestHandler().read( |
437 | + self.request, build.project.name, build.name) |
438 | + self.assertEqual([{'package': 'foo', 'version': '1.2'}], results) |
439 | + |
440 | + def test_private_project_build_manifest_returns_404_for_others(self): |
441 | + build = make_build(is_private=True) |
442 | + make_build_manifest_file(build) |
443 | + user = self._login(factory.make_user()) |
444 | + results = BuildManifestHandler().read( |
445 | + self.request, build.project.name, build.name) |
446 | + self.assertTrue(isinstance(results, HttpResponse)) |
447 | + self.assertEqual(404, results.status_code) |
448 | + |
449 | + |
450 | +class BuildManifestComparisonHandlerTests(BaseHandlerTestCase): |
451 | + |
452 | + def test_public_projects_build_manifest_comparison(self): |
453 | + build = make_build(is_private=False) |
454 | + build2 = factory.make_build_result( |
455 | + project=build.project, builder=factory.make_lexbuilder()) |
456 | + make_build_manifest_file(build) |
457 | + make_build_manifest_file(build2) |
458 | + self.request.GET['build'] = build2.name |
459 | + results = BuildManifestComparisonHandler().read( |
460 | + self.request, build.project.name, build.name) |
461 | + self.assertEqual( |
462 | + [{'changeType': 'no_change', 'target_version': '1.2', |
463 | + 'base_version': '1.2', 'package': 'foo'}], |
464 | + results) |
465 | + |
466 | + def test_private_build_manifest_comparison_is_visible_to_owner(self): |
467 | + build = make_build(is_private=True) |
468 | + build2 = factory.make_build_result( |
469 | + project=build.project, builder=factory.make_lexbuilder()) |
470 | + make_build_manifest_file(build) |
471 | + make_build_manifest_file(build2) |
472 | + user = self._login(build.project.owner) |
473 | + self.request.GET['build'] = build2.name |
474 | + results = BuildManifestComparisonHandler().read( |
475 | + self.request, build.project.name, build.name) |
476 | + self.assertEqual( |
477 | + [{'changeType': 'no_change', 'target_version': '1.2', |
478 | + 'base_version': '1.2', 'package': 'foo'}], |
479 | + results) |
480 | + |
481 | + def test_private_build_manifest_comparison_returns_404_for_others(self): |
482 | + build = make_build(is_private=True) |
483 | + build2 = factory.make_build_result( |
484 | + project=build.project, builder=factory.make_lexbuilder()) |
485 | + make_build_manifest_file(build) |
486 | + make_build_manifest_file(build2) |
487 | + user = self._login(factory.make_user()) |
488 | + self.request.GET['build'] = build2.name |
489 | + results = BuildManifestComparisonHandler().read( |
490 | + self.request, build.project.name, build.name) |
491 | + self.assertTrue(isinstance(results, HttpResponse)) |
492 | + self.assertEqual(404, results.status_code) |
493 | + |
494 | + |
495 | +def make_build(is_private): |
496 | + return factory.make_build_result( |
497 | + project=factory.make_project(is_private=is_private), |
498 | + builder=factory.make_lexbuilder()) |
499 | + |
500 | + |
501 | +def make_build_manifest_file(build): |
502 | + """Create a manifest file where BuildManifestHandler expects to find it.""" |
503 | + manifest_dir = os.path.join(build.result_directory, 'images', 'build') |
504 | + try: |
505 | + os.makedirs(manifest_dir) |
506 | + except OSError, exc: |
507 | + if exc.errno != errno.EEXIST: |
508 | + raise |
509 | + path = os.path.join(manifest_dir, 'build.manifest') |
510 | + with open(path, 'w') as fd: |
511 | + fd.write('foo 1.2') |
512 | |
513 | === modified file 'lib/offspring/web/queuemanager/tests/test_views.py' |
514 | --- lib/offspring/web/queuemanager/tests/test_views.py 2011-12-02 15:32:33 +0000 |
515 | +++ lib/offspring/web/queuemanager/tests/test_views.py 2011-12-02 15:32:33 +0000 |
516 | @@ -1,9 +1,5 @@ |
517 | from django.core.urlresolvers import reverse |
518 | -from django.contrib.auth.models import ( |
519 | - AnonymousUser, |
520 | - Group, |
521 | - Permission, |
522 | - ) |
523 | +from django.contrib.auth.models import AnonymousUser |
524 | from django.http import Http404 |
525 | from django.test import TestCase |
526 | |
527 | @@ -13,6 +9,7 @@ |
528 | ) |
529 | from offspring.web.queuemanager.views import get_possibly_private_object |
530 | from offspring.web.queuemanager.tests.factory import factory |
531 | +from offspring.web.queuemanager.tests.helpers import grant_permission_to_user |
532 | |
533 | |
534 | class Test_get_possibly_private_object(TestCase): |
535 | @@ -259,17 +256,53 @@ |
536 | self.assertEqual([], list(access_group.members.all())) |
537 | |
538 | |
539 | +class ProjectBuildsViewTests(TestCase, ProjectViewTestsMixin): |
540 | + view_path = 'offspring.web.queuemanager.views.builds' |
541 | + |
542 | + def get_expected_page_heading(self, project): |
543 | + return 'Build Records for %s' % project.title |
544 | + |
545 | + def test_public_project(self): |
546 | + project = factory.make_project(is_private=False) |
547 | + build = factory.make_build_result(project=project) |
548 | + response = self.client.get( |
549 | + reverse(self.view_path, args=[project.name])) |
550 | + self.assertContains( |
551 | + response, self.get_expected_page_heading(project), |
552 | + status_code=200, msg_prefix=response.content) |
553 | + |
554 | + |
555 | +class OverallBuildsViewTests(TestCase): |
556 | + view_path = 'offspring.web.queuemanager.views.builds' |
557 | + |
558 | + def test_public_builds_are_shown(self): |
559 | + project = factory.make_project(is_private=False) |
560 | + build = factory.make_build_result(project=project) |
561 | + response = self.client.get(reverse(self.view_path)) |
562 | + self.assertContains( |
563 | + response, build.name, status_code=200, msg_prefix=response.content) |
564 | + |
565 | + def test_private_builds_are_shown_if_user_has_rights(self): |
566 | + project = factory.make_project(is_private=True) |
567 | + build = factory.make_build_result(project=project) |
568 | + user = project.owner |
569 | + self.assertTrue( |
570 | + self.client.login(username=user.username, password=user.username)) |
571 | + response = self.client.get(reverse(self.view_path)) |
572 | + self.assertContains( |
573 | + response, build.name, status_code=200, msg_prefix=response.content) |
574 | + |
575 | + def test_private_builds_are_not_shown_if_user_has_no_rights(self): |
576 | + project = factory.make_project(is_private=True) |
577 | + build = factory.make_build_result(project=project) |
578 | + user = factory.make_user() |
579 | + self.assertTrue( |
580 | + self.client.login(username=user.username, password=user.username)) |
581 | + response = self.client.get(reverse(self.view_path)) |
582 | + self.assertNotContains( |
583 | + response, build.name, status_code=200, msg_prefix=response.content) |
584 | + |
585 | + |
586 | def make_user_and_login(client): |
587 | user = factory.make_user() |
588 | return client.login(username=user.username, password=user.username) |
589 | - |
590 | - |
591 | -def grant_permission_to_user(user, permission): |
592 | - group = Group(name=user.username) |
593 | - group.save() |
594 | - group.permissions.add(Permission.objects.get(codename=permission)) |
595 | - group.save() |
596 | - user.groups.add(group) |
597 | - user.save() |
598 | - return user |
599 | - |
600 | |
601 | === modified file 'lib/offspring/web/queuemanager/views.py' |
602 | --- lib/offspring/web/queuemanager/views.py 2011-12-02 15:32:33 +0000 |
603 | +++ lib/offspring/web/queuemanager/views.py 2011-12-02 15:32:33 +0000 |
604 | @@ -107,13 +107,15 @@ |
605 | context_instance=RequestContext(request)) |
606 | |
607 | def builds(request, projectName=None): |
608 | + user = request.user |
609 | + user_visible_builds = BuildResult.all_objects.accessible_by_user(user) |
610 | if projectName is not None: |
611 | - p = get_object_or_404(Project, pk=projectName) |
612 | - buildResults_list = BuildResult.objects.filter( |
613 | - project = projectName).order_by("finished_at").reverse() |
614 | + p = get_possibly_private_object(user, Project, pk=projectName) |
615 | + buildResults_list = user_visible_builds.filter( |
616 | + project=projectName).order_by("finished_at").reverse() |
617 | else: |
618 | p = None |
619 | - buildResults_list = BuildResult.objects.select_related( |
620 | + buildResults_list = user_visible_builds.select_related( |
621 | 'builder', 'requestor', 'project').order_by("finished_at").reverse() |
622 | paginator = Paginator(buildResults_list, 15) |
623 | |
624 | @@ -127,8 +129,12 @@ |
625 | except (EmptyPage, InvalidPage): |
626 | buildResults = paginator.page(paginator.num_pages) |
627 | |
628 | + is_private = False |
629 | + if p is not None and p.is_private: |
630 | + is_private = True |
631 | pageData = { |
632 | 'project' : p, |
633 | + 'is_private' : is_private, |
634 | 'build_results' : buildResults, |
635 | 'pillar' : 'builds' |
636 | } |
637 | @@ -232,7 +238,9 @@ |
638 | request.user) |
639 | p = get_possibly_private_object( |
640 | request.user, user_visible_objects, pk=projectName) |
641 | - project_build_results = BuildResult.objects.filter( |
642 | + user_visible_builds = BuildResult.all_objects.accessible_by_user( |
643 | + request.user) |
644 | + project_build_results = user_visible_builds.filter( |
645 | project = p).exclude(result = None) |
646 | build_stats = { |
647 | 'fail_count' : project_build_results.filter(result = ProjectBuildStates.FAILED).count(), |
648 | |
649 | === modified file 'lib/offspring/web/settings.py' |
650 | --- lib/offspring/web/settings.py 2011-11-18 15:45:06 +0000 |
651 | +++ lib/offspring/web/settings.py 2011-12-02 15:32:33 +0000 |
652 | @@ -131,6 +131,3 @@ |
653 | CELERY_RESULT_BACKEND = 'djcelery.backends.database.DatabaseBackend' |
654 | CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler' |
655 | djcelery.setup_loader() |
656 | - |
657 | -# Path to build results |
658 | -BUILDRESULTS_DIRECTORY = '/srv/builds/' |
659 | |
660 | === modified file 'lib/offspring/web/settings_production.py' |
661 | --- lib/offspring/web/settings_production.py 2011-11-30 14:15:52 +0000 |
662 | +++ lib/offspring/web/settings_production.py 2011-12-02 15:32:33 +0000 |
663 | @@ -16,6 +16,3 @@ |
664 | EMAIL_HOST = 'localhost' |
665 | |
666 | MEDIA_URL = 'https://offspring.com/assets/' |
667 | - |
668 | -# Path to build results |
669 | -BUILDRESULTS_DIRECTORY = '/srv/offspring.com/www/builds/' |