Merge lp:~salgado/offspring/acl-editor into lp:~linaro-automation/offspring/linaro

Proposed by Guilherme Salgado
Status: Merged
Approved by: James Tunnicliffe
Approved revision: no longer in the source branch.
Merge reported by: Guilherme Salgado
Merged at revision: not available
Proposed branch: lp:~salgado/offspring/acl-editor
Merge into: lp:~linaro-automation/offspring/linaro
Prerequisite: lp:~salgado/offspring/private-projects-views
Diff against target: 276 lines (+202/-1)
5 files modified
lib/offspring/web/queuemanager/forms.py (+7/-1)
lib/offspring/web/queuemanager/tests/test_views.py (+74/-0)
lib/offspring/web/queuemanager/views.py (+55/-0)
lib/offspring/web/templates/queuemanager/project_acl.html (+64/-0)
lib/offspring/web/urls.py (+2/-0)
To merge this branch: bzr merge lp:~salgado/offspring/acl-editor
Reviewer Review Type Date Requested Status
James Tunnicliffe (community) Approve
Review via email: mp+78857@code.launchpad.net

Description of the change

Add a new page (+acl) to edit the list of people who can see a given project. For now there are no links to that page but my next branch will add that.

To post a comment you must log in.
Revision history for this message
James Tunnicliffe (dooferlad) wrote :

Good stuff.

review: Approve
Revision history for this message
Guilherme Salgado (salgado) wrote :

In fact this was merged into our integration branch (lp:~linaro-infrastructure/offspring/private-builds)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/offspring/web/queuemanager/forms.py'
2--- lib/offspring/web/queuemanager/forms.py 2011-03-03 00:06:58 +0000
3+++ lib/offspring/web/queuemanager/forms.py 2011-10-10 15:22:27 +0000
4@@ -1,8 +1,10 @@
5 # Copyright 2010 Canonical Ltd. This software is licensed under the
6 # GNU Affero General Public License version 3 (see the file LICENSE).
7
8+from django.contrib.auth.models import User
9 from django.db import models
10-from django.forms import ModelChoiceField, ModelForm, Textarea, TextInput
11+from django.forms import (
12+ Form, ModelChoiceField, ModelForm, Textarea, TextInput)
13 from django.forms import fields
14
15 from offspring.web.queuemanager.models import (
16@@ -47,6 +49,10 @@
17 exclude = ('name', 'priority', 'is_active')
18
19
20+class AccessGroupMemberForm(Form):
21+ new_user = ModelChoiceField(queryset=User.objects, required=False)
22+
23+
24 class ReleaseForm(ModelForm):
25 class Meta:
26 model = Release
27
28=== modified file 'lib/offspring/web/queuemanager/tests/test_views.py'
29--- lib/offspring/web/queuemanager/tests/test_views.py 2011-10-10 15:22:27 +0000
30+++ lib/offspring/web/queuemanager/tests/test_views.py 2011-10-10 15:22:27 +0000
31@@ -185,6 +185,80 @@
32 self.assertEqual(404, response.status_code)
33
34
35+class TestProjectACLView(TestCase):
36+
37+ def test_is_visible_to_owner(self):
38+ project = factory.makeProject(is_private=True)
39+ user = project.owner
40+ grant_permission_to_user(user, 'change_project')
41+ self.assertTrue(
42+ self.client.login(username=user.username, password=user.username))
43+ response = self.client.get(
44+ reverse('offspring.web.queuemanager.views.project_acl',
45+ args=[project.name]))
46+ self.assertContains(
47+ response, 'Update ACLs for %s' % project.title.capitalize(),
48+ status_code=200, msg_prefix=response.content)
49+
50+ def test_is_visible_to_access_group_member(self):
51+ user = factory.makeUser()
52+ grant_permission_to_user(user, 'change_project')
53+ group = factory.makeAccessGroup([user])
54+ project = factory.makeProject(is_private=True, access_groups=[group])
55+ self.assertTrue(
56+ self.client.login(username=user.username, password=user.username))
57+ response = self.client.get(
58+ reverse('offspring.web.queuemanager.views.project_acl',
59+ args=[project.name]))
60+ self.assertContains(
61+ response, 'Update ACLs for %s' % project.title.capitalize(),
62+ status_code=200, msg_prefix=response.content)
63+
64+ def test_is_not_visible_to_others(self):
65+ user = factory.makeUser()
66+ grant_permission_to_user(user, 'change_project')
67+ project = factory.makeProject(is_private=True)
68+ self.assertTrue(
69+ self.client.login(username=user.username, password=user.username))
70+ response = self.client.get(
71+ reverse('offspring.web.queuemanager.views.project_acl',
72+ args=[project.name]))
73+ self.assertEqual(404, response.status_code)
74+
75+ def test_add_new_user(self):
76+ project = factory.makeProject(is_private=True)
77+ user = project.owner
78+ grant_permission_to_user(user, 'change_project')
79+ self.assertTrue(
80+ self.client.login(username=user.username, password=user.username))
81+ member = factory.makeUser()
82+ data = {'new_user': member.id}
83+ response = self.client.post(
84+ reverse('offspring.web.queuemanager.views.project_acl',
85+ args=[project.name]),
86+ data)
87+ self.assertEqual(200, response.status_code)
88+ access_group = project.access_groups.all()[0]
89+ self.assertEqual([member], list(access_group.members.all()))
90+
91+ def test_remove_member(self):
92+ member = factory.makeUser()
93+ group = factory.makeAccessGroup([member])
94+ project = factory.makeProject(is_private=True, access_groups=[group])
95+ user = project.owner
96+ grant_permission_to_user(user, 'change_project')
97+ self.assertTrue(
98+ self.client.login(username=user.username, password=user.username))
99+ data = {'disallow': 'Disallow', member.username: 'on'}
100+ response = self.client.post(
101+ reverse('offspring.web.queuemanager.views.project_acl',
102+ args=[project.name]),
103+ data)
104+ self.assertEqual(200, response.status_code)
105+ access_group = project.access_groups.all()[0]
106+ self.assertEqual([], list(access_group.members.all()))
107+
108+
109 def make_user_and_login(client):
110 user = factory.makeUser()
111 return client.login(username=user.username, password=user.username)
112
113=== modified file 'lib/offspring/web/queuemanager/views.py'
114--- lib/offspring/web/queuemanager/views.py 2011-10-10 15:22:27 +0000
115+++ lib/offspring/web/queuemanager/views.py 2011-10-10 15:22:27 +0000
116@@ -41,9 +41,12 @@
117
118 from pygooglechart import PieChart3D
119
120+from django_group_access.models import AccessGroup
121+
122 from offspring import config
123 from offspring.enums import ProjectBuildStates
124 from offspring.web.queuemanager.forms import (
125+ AccessGroupMemberForm,
126 CreateProjectForm,
127 EditProjectForm,
128 LaunchpadProjectForm,
129@@ -257,6 +260,58 @@
130 'queuemanager/project_details.html', pageData,
131 context_instance=RequestContext(request))
132
133+
134+@permission_required('queuemanager.change_project')
135+def project_acl(request, projectName):
136+ user_visible_objects = Project.all_objects.accessible_by_user(
137+ request.user)
138+ project = get_possibly_private_object(
139+ request.user, user_visible_objects, pk=projectName)
140+ access_group = None
141+ allowed_users = []
142+ if len(project.access_groups.all()) > 0:
143+ # We always use the first access group because there's no way for
144+ # users to register more than one access group for any given project.
145+ access_group = project.access_groups.all()[0]
146+ allowed_users = access_group.members.all()
147+ if request.method == 'POST':
148+ form = AccessGroupMemberForm(request.POST)
149+ if form.is_valid():
150+ # A form submission can be either to add a new member or to remove
151+ # an existing one.
152+ if form.data.get('new_user'):
153+ if access_group is None:
154+ # This project has no access group set up yet, so we
155+ # create one.
156+ access_group = AccessGroup(name=project.name)
157+ access_group.save()
158+ project.access_groups.add(access_group)
159+ project.save()
160+ access_group.members.add(form.cleaned_data['new_user'])
161+ access_group.save()
162+ else:
163+ assert 'disallow' in form.data.keys(), ("Unknown form action")
164+ for user in allowed_users:
165+ if user.username in form.data.keys():
166+ access_group.members.remove(user)
167+ access_group.save()
168+ # We don't redirect on a successful form submission because most
169+ # of the time users will want to make multiple changes to the ACL.
170+ allowed_users = access_group.members.all()
171+ form = AccessGroupMemberForm()
172+ else:
173+ form = AccessGroupMemberForm()
174+ pageData = {
175+ 'csrf_token' : csrf.get_token(request),
176+ 'project' : project,
177+ 'form': form,
178+ 'allowed_users': allowed_users,
179+ }
180+ return render_to_response(
181+ 'queuemanager/project_acl.html', pageData,
182+ context_instance=RequestContext(request))
183+
184+
185 def projectgroup_details(request, projectGroupName):
186 pg = get_object_or_404(
187 ProjectGroup, pk=projectGroupName)
188
189=== added file 'lib/offspring/web/templates/queuemanager/project_acl.html'
190--- lib/offspring/web/templates/queuemanager/project_acl.html 1970-01-01 00:00:00 +0000
191+++ lib/offspring/web/templates/queuemanager/project_acl.html 2011-10-10 15:22:27 +0000
192@@ -0,0 +1,64 @@
193+{% extends "base.html" %}
194+
195+{% block header_css %}
196+<link rel="stylesheet" type="text/css" href="/media/css/forms.css" />
197+{% endblock %}
198+
199+{% block title %}
200+Update ACLs for {{project.title|capfirst}}
201+{% endblock %}
202+
203+{% block content %}
204+ {% if project.is_private %}
205+ <p>These are the only users who can see this project or anything related
206+ to it.</p>
207+ {% else %}
208+ <p>This project is not private, so this access control list has no
209+ effect.</p>
210+ {% endif %}
211+ <form method="POST" action="">{% csrf_token %}
212+ <div class="module aligned ">
213+ {% for field in form %}
214+ <div class="form-row {% if line.errors %} errors{% endif %} {{ field.name }}">
215+ <div>
216+ {{ field.label_tag }}
217+ {{ field }}
218+ {% if field.field.field.help_text %}
219+ <p class="help">{{ field.field.field.help_text|safe }}</p>
220+ {% endif %}
221+ <input type="submit" value="Add" class="default" name="_save"/>
222+ </div>
223+ {{ field.errors }}
224+ </div>
225+ {% endfor %}
226+ <h3>Currently allowed users</h3>
227+ <table>
228+ {% for user in allowed_users %}
229+ <tr>
230+ <td>
231+ <input type="checkbox" name="{{ user.username }}" />
232+ </td>
233+ <td>
234+ {% if user.get_full_name %}
235+ {{ user.get_full_name }}
236+ {% else %}
237+ {{ user.username }}
238+ {% endif %}
239+ ({{ user.email }})
240+ </td>
241+ </tr>
242+ {% empty %}
243+ <div>None</div>
244+ {% endfor %}
245+ </table>
246+ <div class="submit-row" style="overflow: auto;">
247+ <input type="submit" value="Disallow Selected Users" name="disallow" />
248+ <input type="button" value="Cancel" class="default" name="_cancel"
249+ OnClick="window.location.href = '{% url offspring.web.queuemanager.views.project_details project.name %}';"/>
250+ </div>
251+ </div>
252+ </form>
253+{% endblock %}
254+
255+{% block two-columns %}
256+{% endblock %}
257
258=== modified file 'lib/offspring/web/urls.py'
259--- lib/offspring/web/urls.py 2011-08-12 01:45:45 +0000
260+++ lib/offspring/web/urls.py 2011-10-10 15:22:27 +0000
261@@ -28,6 +28,7 @@
262 ReleaseHandler
263 )
264 from offspring.web.queuemanager.views import (
265+ project_acl,
266 project_create,
267 project_edit,
268 secure_object_list,
269@@ -84,6 +85,7 @@
270 (r'^project-groups/(?P<projectGroupName>[^/]+)/$', 'offspring.web.queuemanager.views.projectgroup_details'),
271 url(r'^projects/\+add/$', project_create, name="project_create"),
272 url(r'^projects/(?P<projectName>[^/]+)/\+edit$', project_edit, name="project_edit"),
273+ url(r'^projects/(?P<projectName>[^/]+)/\+acl$', project_acl, name="project_acl"),
274 (r'^projects/(?P<projectName>[^/]+)/sources\.list$', 'offspring.web.queuemanager.views.project_development_sourcesList'),
275 (r'^projects/(?P<projectName>[^/]+)/\+api/subscription/$', projectNotificationSubscription_handler),
276 (r'^projects/(?P<projectName>[^/]+)/\+api/releases/$', release_handler),

Subscribers

People subscribed via source and target branches