Merge lp:~salgado/offspring/disable-subscription-for-private-projects into lp:~linaro-automation/offspring/private-builds

Proposed by Guilherme Salgado
Status: Superseded
Proposed branch: lp:~salgado/offspring/disable-subscription-for-private-projects
Merge into: lp:~linaro-automation/offspring/private-builds
Diff against target: 338 lines (+164/-26)
8 files modified
lib/offspring/master/models.py (+1/-0)
lib/offspring/master/notifications.py (+3/-0)
lib/offspring/master/tests.py (+39/-0)
lib/offspring/web/queuemanager/handlers.py (+9/-9)
lib/offspring/web/queuemanager/tests/helpers.py (+14/-0)
lib/offspring/web/queuemanager/tests/test_handlers.py (+87/-0)
lib/offspring/web/queuemanager/tests/test_views.py (+2/-16)
lib/offspring/web/templates/queuemanager/project_details.html (+9/-1)
To merge this branch: bzr merge lp:~salgado/offspring/disable-subscription-for-private-projects
Reviewer Review Type Date Requested Status
Linaro Infrastructure Pending
Review via email: mp+79604@code.launchpad.net

Description of the change

This branch disables the ability to subscribe to notifications of private projects as well as the sending of notifications about private projects

To post a comment you must log in.
86. By Guilherme Salgado

Remove 4 unused methods (one from Project and 3 from ProjectGroup)

87. By Cody A.W. Somerville

Deprecate shell script configuration file offspring-builder.config for builder component and build archiver script - instead store that configuration in offspring.cfg and have offspring-builder-config script that will output shell environment variables to be set by components of Offspring still written in shell. Kudos to Michael Hudson and Guilherme Salgado from Linaro. N.B. Project build configuration in build configuration branches are still written in shell.

88. By Guilherme Salgado

Add the hwpack wrapper used by Linaro

89. By Guilherme Salgado

Add an anonymous object factory for queuemanager tests

90. By Guilherme Salgado

Add support for private objects to web.queuemanger, with a custom API for querying only the objects a given user is allowed to see and helper methods to check if a given object is visible to a given user

91. By Kevin McDermott

Merge database-testing [r=salgado] [f=891557]

This adds a test infrastructure for the "master" part of offspring, including
setting up the database tables needed and support for fixtures.

In addition, there new tests added for the master code, and the notifications
that are sent.

Also, the configuration mechanism has been replaced by a simple ConfigParser
implementation.

92. By Kevin McDermott

Merge add-path-independence [r=salgado] [f=897203]

This changes the default file used in Offspring, to use a file sourced from the
root of the offspring Python source files.

The path to the configuration file can still be explicitly set either through
the environment or explicitly on the command-line.

93. By Kevin McDermott

Merge slave-testing [r=jedimike] [f=898118]

This adds tests for the Offspring LexBuilderSlave functionality.

94. By Kevin McDermott

Merge fix-base-dir-in-config [r=salgado] [f=899220]

This fixes get_configuration() to only overwrite the base_dir in the
configuration object returned in the event that there's no base_dir already
set.

95. By Kevin McDermott

Merge slave-testing-server [r=salgado] [f=898118]

This adds tests for the LexbuilderSlaveServer.

96. By Kevin McDermott

Add coverage make targets for slave and master.

97. By Kevin McDermott

Missed config gets.

98. By Guilherme Salgado

Make project and build views return a 404 if the user is not allowed to see that private project/build

99. By Kevin McDermott

Merge passing-ssh-key-to-slave2 [r=bigkevmcd] [a=jamestunnicliff]

This adds support for passing an SSH key to the slave builder, to use when
checking out configurations.

100. By Kevin McDermott

Add test-web-coverage as a target.

101. By Guilherme Salgado

Add a new page (+acl) to edit the list of people who can see a given private project.

102. By Kevin McDermott

Don't import tests otherwise they run twice.

103. By Kevin McDermott

Merge error-in-queuemanager-views [r=salgado] [f=900337]

This adds tests for the LaunchpadProject form, and removes an error in the view
code for creating LaunchpadProjects.

104. By Guilherme Salgado

Change the builds() view to show private builds if the user is allowed to see them.

105. By Guilherme Salgado

Update the piston handlers to include private objects the user is allowed to see.

106. By Kevin McDermott

Merge add-queue-metrics [r=cody,schwuk] [f=902183]

This adds the core queue-metrics logic, calculating the average build time
either for a Project, or for all Projects, over a configurable period of time.

It also adds a new management command build_metrics which outputs some basic
metrics.

107. By Cody A.W. Somerville

Updated archive-builds script to include hwpacks generated by linaro-media-create in artifacts that are pruned (LP #819371).

108. By Kevin McDermott

Merge slave-testing-integration [r=Cody] [f=898118]

This adds test coverage for offspring.slave.slave.

109. By Guilherme Salgado

Update list views to include private objects the user is allowed to see or
redact information about the ones the user is not allowed to see.

The project list view hides the projects the user is not allowed to see
whereas the builder list redacts information about current builds when it's
for a project the user is not allowed to see

110. By Guilherme Salgado

Update the builder_details view to omit details of the current job if the user
has no rights to see it.

Also shows a small padlock icon next to private projects on both the list of
projects and the list of builds

111. By Kevin McDermott

Merge add-queue-wait-time [r=salgado] [f=902183]

This implements queue wait time metric to the gathered metrics.

112. By Kevin McDermott

Merge non-scheduled-builds [r=salgado] [f=902183]

This adds support for non-scheduled (automated) builds to the metrics
determination.

113. By Guilherme Salgado

Update the build failures sidebar to skip private builds the user is not allowed to see, and the queued-builds and build-farm sidebars to simply state it's a private build (without any other information) when the user is not allowed to see them

114. By Guilherme Salgado

Make sure Lexbuilders with no current_job are considered public

115. By Guilherme Salgado

Make sure we can't have a private project without an owner, as that could render them completely inaccessible

116. By Guilherme Salgado

Disable subscriptions and notifications to private projects by not showing the Subscribe link for private projects and refraining from sending any notification for builds of private projects.

117. By Guilherme Salgado

merge trunk

Unmerged revisions

117. By Guilherme Salgado

merge trunk

116. By Guilherme Salgado

Disable subscriptions and notifications to private projects by not showing the Subscribe link for private projects and refraining from sending any notification for builds of private projects.

115. By Guilherme Salgado

Make sure we can't have a private project without an owner, as that could render them completely inaccessible

114. By Guilherme Salgado

Make sure Lexbuilders with no current_job are considered public

113. By Guilherme Salgado

Update the build failures sidebar to skip private builds the user is not allowed to see, and the queued-builds and build-farm sidebars to simply state it's a private build (without any other information) when the user is not allowed to see them

112. By Kevin McDermott

Merge non-scheduled-builds [r=salgado] [f=902183]

This adds support for non-scheduled (automated) builds to the metrics
determination.

111. By Kevin McDermott

Merge add-queue-wait-time [r=salgado] [f=902183]

This implements queue wait time metric to the gathered metrics.

110. By Guilherme Salgado

Update the builder_details view to omit details of the current job if the user
has no rights to see it.

Also shows a small padlock icon next to private projects on both the list of
projects and the list of builds

109. By Guilherme Salgado

Update list views to include private objects the user is allowed to see or
redact information about the ones the user is not allowed to see.

The project list view hides the projects the user is not allowed to see
whereas the builder list redacts information about current builds when it's
for a project the user is not allowed to see

108. By Kevin McDermott

Merge slave-testing-integration [r=Cody] [f=898118]

This adds test coverage for offspring.slave.slave.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/offspring/master/models.py'
--- lib/offspring/master/models.py 2011-09-23 14:01:26 +0000
+++ lib/offspring/master/models.py 2011-10-17 19:26:36 +0000
@@ -157,6 +157,7 @@
157 title = Unicode()157 title = Unicode()
158 priority = Int(default=0)158 priority = Int(default=0)
159 is_active = Bool(default=True)159 is_active = Bool(default=True)
160 is_private = Bool(default=False)
160 launchpad_project_id = Unicode()161 launchpad_project_id = Unicode()
161 launchpad_project = Reference(launchpad_project_id, "LaunchpadProject.name")162 launchpad_project = Reference(launchpad_project_id, "LaunchpadProject.name")
162 suite = Unicode()163 suite = Unicode()
163164
=== modified file 'lib/offspring/master/notifications.py'
--- lib/offspring/master/notifications.py 2010-11-29 08:27:24 +0000
+++ lib/offspring/master/notifications.py 2011-10-17 19:26:36 +0000
@@ -88,6 +88,9 @@
88def notify_buildresult(build_result):88def notify_buildresult(build_result):
89 project = build_result.project89 project = build_result.project
90 builder = build_result.builder90 builder = build_result.builder
91 if project.is_private:
92 # We don't support subscriptions for private projects.
93 return
91 94
92 build_date, build_id = build_result.name.rsplit('-', 1)95 build_date, build_id = build_result.name.rsplit('-', 1)
93 build_url = "%s/%s/%s/%s" % (offspring.config.web('build_results_uri'), project.name, build_date, build_id)96 build_url = "%s/%s/%s/%s" % (offspring.config.web('build_results_uri'), project.name, build_date, build_id)
9497
=== modified file 'lib/offspring/master/tests.py'
--- lib/offspring/master/tests.py 2011-09-08 19:12:29 +0000
+++ lib/offspring/master/tests.py 2011-10-17 19:26:36 +0000
@@ -5,7 +5,12 @@
5import unittest5import unittest
66
7from offspring import config7from offspring import config
8from offspring.master.models import (
9 Project,
10 ProjectNotificationSubscription,
11 )
8from offspring.master.notifications import (12from offspring.master.notifications import (
13 notify_buildresult,
9 notify_crash,14 notify_crash,
10 notify_problem,15 notify_problem,
11)16)
@@ -20,6 +25,12 @@
20 self.mails.append((sender, rcpt, msg))25 self.mails.append((sender, rcpt, msg))
2126
2227
28class FakeLexBuilder(object):
29
30 def __init__(self, name):
31 self.name = name
32
33
23class Factory(object):34class Factory(object):
2435
25 def __init__(self):36 def __init__(self):
@@ -29,6 +40,13 @@
29 self.counter += 140 self.counter += 1
30 return 'str%s' % self.counter41 return 'str%s' % self.counter
3142
43 def makeProject(self, is_private=False):
44 name = self.getUniqueString()
45 project = Project(name=name)
46 project.title = name.decode('utf-8')
47 project.is_private = is_private
48 return project
49
3250
33class TestCaseWithFactory(unittest.TestCase):51class TestCaseWithFactory(unittest.TestCase):
3452
@@ -119,3 +137,24 @@
119 from_header = mailer.mails[0][0]137 from_header = mailer.mails[0][0]
120 sender_real_name, sender_addr = email.utils.parseaddr(from_header)138 sender_real_name, sender_addr = email.utils.parseaddr(from_header)
121 self.assertEqual(addr, sender_addr)139 self.assertEqual(addr, sender_addr)
140
141
142class FakeBuildResult(object):
143
144 def __init__(self, project):
145 self.project = project
146 self.builder = None
147
148
149class TestNotifyBuildResult(TestCaseWithFactory):
150
151 def test_private_project(self):
152 # For simplicity, we don't support subscriptions for private projects,
153 # so no notifications are sent here even though there is a project
154 # subscription.
155 mailer = StubMailer()
156 project = self.factory.makeProject(is_private=True)
157 project.subscriptions = [ProjectNotificationSubscription()]
158 build = FakeBuildResult(project)
159 notify_buildresult(build)
160 self.assertEquals([], mailer.mails)
122161
=== modified file 'lib/offspring/web/queuemanager/handlers.py'
--- lib/offspring/web/queuemanager/handlers.py 2011-10-13 23:23:41 +0000
+++ lib/offspring/web/queuemanager/handlers.py 2011-10-17 19:26:36 +0000
@@ -154,7 +154,6 @@
154 return results154 return results
155155
156156
157# TODO: Must be made privacy-aware.
158class BuildRequestHandler(BaseHandler):157class BuildRequestHandler(BaseHandler):
159 allowed_methods = ('GET', 'POST', 'DELETE')158 allowed_methods = ('GET', 'POST', 'DELETE')
160 model = BuildRequest159 model = BuildRequest
@@ -162,10 +161,10 @@
162161
163 def read(self, request, projectName=None, request_id=None):162 def read(self, request, projectName=None, request_id=None):
164 try:163 try:
164 requests = BuildRequest.all_objects.accessible_by_user(
165 request.user)
165 if projectName is not None:166 if projectName is not None:
166 requests = BuildRequest.objects.filter(project__name=projectName)167 requests = requests.filter(project__name=projectName)
167 else:
168 requests = BuildRequest.objects
169 except:168 except:
170 return rc.NOT_FOUND169 return rc.NOT_FOUND
171 if request_id is not None:170 if request_id is not None:
@@ -177,12 +176,12 @@
177 def delete(self, request, projectName=None, request_id=None):176 def delete(self, request, projectName=None, request_id=None):
178 if request.user.has_perm("queuemanager.can_build"):177 if request.user.has_perm("queuemanager.can_build"):
179 try:178 try:
179 requests = BuildRequest.all_objects.accessible_by_user(
180 request.user)
180 if projectName is not None:181 if projectName is not None:
181 requests = BuildRequest.objects.filter(project__name=projectName)182 requests = requests.filter(project__name=projectName)
182 else:
183 requests = BuildRequest.objects
184 except:183 except:
185 return RC.NOT_FOUND184 return rc.NOT_FOUND
186 if request_id is not None:185 if request_id is not None:
187 try:186 try:
188 requests.get(pk=request_id).delete()187 requests.get(pk=request_id).delete()
@@ -202,7 +201,8 @@
202 def create(self, request, projectName):201 def create(self, request, projectName):
203 if request.user.has_perm("queuemanager.can_build"):202 if request.user.has_perm("queuemanager.can_build"):
204 try:203 try:
205 p = Project.objects.get(pk=projectName)204 p = Project.all_objects.accessible_by_user(request.user).get(
205 pk=projectName)
206 if request.POST.has_key('build_reason'):206 if request.POST.has_key('build_reason'):
207 request = BuildRequest.queue_build(p, request.user, reason=request.POST['build_reason'], scoreBonus=25)207 request = BuildRequest.queue_build(p, request.user, reason=request.POST['build_reason'], scoreBonus=25)
208 else:208 else:
209209
=== added file 'lib/offspring/web/queuemanager/tests/helpers.py'
--- lib/offspring/web/queuemanager/tests/helpers.py 1970-01-01 00:00:00 +0000
+++ lib/offspring/web/queuemanager/tests/helpers.py 2011-10-17 19:26:36 +0000
@@ -0,0 +1,14 @@
1from django.contrib.auth.models import (
2 Group,
3 Permission,
4 )
5
6
7def grant_permission_to_user(user, permission):
8 group = Group(name=user.username)
9 group.save()
10 group.permissions.add(Permission.objects.get(codename=permission))
11 group.save()
12 user.groups.add(group)
13 user.save()
14 return user
015
=== modified file 'lib/offspring/web/queuemanager/tests/test_handlers.py'
--- lib/offspring/web/queuemanager/tests/test_handlers.py 2011-10-13 23:16:02 +0000
+++ lib/offspring/web/queuemanager/tests/test_handlers.py 2011-10-17 19:26:36 +0000
@@ -6,13 +6,18 @@
6from django.test import TestCase6from django.test import TestCase
7from django.contrib.sessions.middleware import SessionMiddleware7from django.contrib.sessions.middleware import SessionMiddleware
88
9from piston.utils import rc
10
11from offspring.web.queuemanager.models import BuildRequest
9from offspring.web.queuemanager.handlers import (12from offspring.web.queuemanager.handlers import (
10 BuildManifestComparisonHandler,13 BuildManifestComparisonHandler,
11 BuildManifestHandler,14 BuildManifestHandler,
15 BuildRequestHandler,
12 BuildResultHandler,16 BuildResultHandler,
13 ReleaseHandler,17 ReleaseHandler,
14 )18 )
15from offspring.web.queuemanager.tests.factory import factory19from offspring.web.queuemanager.tests.factory import factory
20from offspring.web.queuemanager.tests.helpers import grant_permission_to_user
1621
1722
18class BaseHandlerTestCase(TestCase):23class BaseHandlerTestCase(TestCase):
@@ -97,6 +102,88 @@
97 self.assertEqual(0, results.count())102 self.assertEqual(0, results.count())
98103
99104
105class BuildRequestHandlerTests(BaseHandlerTestCase):
106
107 def test_public_build_request_is_visible_to_anyone(self):
108 job = factory.makeBuildRequest(
109 project=factory.makeProject(is_private=False))
110 results = BuildRequestHandler().read(
111 self.request, projectName=job.project.name, request_id=job.id)
112 self.assertEqual(job, results)
113
114 def test_private_build_request_is_visible_to_owner(self):
115 job = factory.makeBuildRequest(
116 project=factory.makeProject(is_private=True))
117 self._login(job.project.owner)
118 results = BuildRequestHandler().read(
119 self.request, projectName=job.project.name, request_id=job.id)
120 self.assertEqual(job, results)
121
122 def test_private_build_request_is_not_visible_to_others(self):
123 job = factory.makeBuildRequest(
124 project=factory.makeProject(is_private=True))
125 self._login(factory.makeUser())
126 self.assertRaises(
127 BuildRequest.DoesNotExist,
128 BuildRequestHandler().read,
129 self.request, projectName=job.project.name, request_id=job.id)
130
131 def test_new_build_request_on_public_project(self):
132 project = factory.makeProject(is_private=False)
133 self.assertCreateReturnCode(
134 project, factory.makeUser(), rc.CREATED.status_code)
135
136 def test_owner_requests_new_build_on_private_project(self):
137 project = factory.makeProject(is_private=True)
138 self.assertCreateReturnCode(
139 project, project.owner, rc.CREATED.status_code)
140
141 def test_other_user_requests_new_build_on_private_project(self):
142 project = factory.makeProject(is_private=True)
143 self.assertCreateReturnCode(
144 project, factory.makeUser(), rc.BAD_REQUEST.status_code)
145
146 def test_delete_build_request_on_public_project(self):
147 job = factory.makeBuildRequest(
148 project=factory.makeProject(is_private=False))
149 self.assertDeleteReturnCode(
150 job, factory.makeUser(), rc.DELETED.status_code)
151
152 def test_owner_deletes_build_request_on_private_project(self):
153 job = factory.makeBuildRequest(
154 project=factory.makeProject(is_private=True))
155 self.assertDeleteReturnCode(
156 job, job.project.owner, rc.DELETED.status_code)
157
158 def test_other_user_deletes_build_request_on_private_project(self):
159 job = factory.makeBuildRequest(
160 project=factory.makeProject(is_private=True))
161 self.assertDeleteReturnCode(
162 job, factory.makeUser(), rc.NOT_FOUND.status_code)
163
164 def assertCreateReturnCode(self, project, user, return_code):
165 """Assert that BuildRequestHandler.create() returns the given code.
166
167 Also grant the given user the 'can_build' permission and logs it in.
168 """
169 grant_permission_to_user(user, 'can_build')
170 self._login(user)
171 result = BuildRequestHandler().create(
172 self.request, projectName=project.name)
173 self.assertEqual(return_code, result.status_code)
174
175 def assertDeleteReturnCode(self, job, user, return_code):
176 """Assert that BuildRequestHandler.delete() returns the given code.
177
178 Also grant the given user the 'can_build' permission and logs it in.
179 """
180 grant_permission_to_user(user, 'can_build')
181 self._login(user)
182 result = BuildRequestHandler().delete(
183 self.request, projectName=job.project.name, request_id=job.id)
184 self.assertEqual(return_code, result.status_code)
185
186
100class ReleaseHandlerTests(BaseHandlerTestCase):187class ReleaseHandlerTests(BaseHandlerTestCase):
101188
102 def test_public_project_release(self):189 def test_public_project_release(self):
103190
=== modified file 'lib/offspring/web/queuemanager/tests/test_views.py'
--- lib/offspring/web/queuemanager/tests/test_views.py 2011-10-10 21:15:48 +0000
+++ lib/offspring/web/queuemanager/tests/test_views.py 2011-10-17 19:26:36 +0000
@@ -1,9 +1,5 @@
1from django.core.urlresolvers import reverse1from django.core.urlresolvers import reverse
2from django.contrib.auth.models import (2from django.contrib.auth.models import AnonymousUser
3 AnonymousUser,
4 Group,
5 Permission,
6 )
7from django.http import Http4043from django.http import Http404
8from django.test import TestCase4from django.test import TestCase
95
@@ -13,6 +9,7 @@
13 )9 )
14from offspring.web.queuemanager.views import get_possibly_private_object10from offspring.web.queuemanager.views import get_possibly_private_object
15from offspring.web.queuemanager.tests.factory import factory11from offspring.web.queuemanager.tests.factory import factory
12from offspring.web.queuemanager.tests.helpers import grant_permission_to_user
1613
1714
18class Test_get_possibly_private_object(TestCase):15class Test_get_possibly_private_object(TestCase):
@@ -309,14 +306,3 @@
309def make_user_and_login(client):306def make_user_and_login(client):
310 user = factory.makeUser()307 user = factory.makeUser()
311 return client.login(username=user.username, password=user.username)308 return client.login(username=user.username, password=user.username)
312
313
314def grant_permission_to_user(user, permission):
315 group = Group(name=user.username)
316 group.save()
317 group.permissions.add(Permission.objects.get(codename=permission))
318 group.save()
319 user.groups.add(group)
320 user.save()
321 return user
322
323309
=== modified file 'lib/offspring/web/templates/queuemanager/project_details.html'
--- lib/offspring/web/templates/queuemanager/project_details.html 2011-10-10 19:42:14 +0000
+++ lib/offspring/web/templates/queuemanager/project_details.html 2011-10-17 19:26:36 +0000
@@ -537,8 +537,16 @@
537 contents:"${isSubscribed ? 'Unsubscribe' : 'Subscribe'} to Notifications",537 contents:"${isSubscribed ? 'Unsubscribe' : 'Subscribe'} to Notifications",
538 dynamicContents:true,538 dynamicContents:true,
539 icon: "/assets/images/mail--plus.png",539 icon: "/assets/images/mail--plus.png",
540{% if not user.is_authenticated %}
541 prompt: "You must login to manage your project build notification subscription",
542 disabled: true,
543{% else %} {% if project.is_private %}
544 prompt: "Build notification subscription disabled for private projects",
545 disabled: true,
546{% else %}
540 prompt: "Manage project build notification subscription",547 prompt: "Manage project build notification subscription",
541 disabled: {% if user.is_authenticated %}false{% else %}true{% endif %},548 disabled: false,
549{% endif %} {% endif %}
542 click: function() {550 click: function() {
543 toggle_subscription();551 toggle_subscription();
544 return false;552 return false;

Subscribers

People subscribed via source and target branches