Merge lp:~danilo/launchpad/bug728370-nondirect-subs into lp:launchpad

Proposed by Данило Шеган
Status: Merged
Approved by: Данило Шеган
Approved revision: no longer in the source branch.
Merged at revision: 12818
Proposed branch: lp:~danilo/launchpad/bug728370-nondirect-subs
Merge into: lp:launchpad
Prerequisite: lp:~danilo/launchpad/bug728370
Diff against target: 1252 lines (+1222/-4)
4 files modified
lib/lp/bugs/javascript/subscription.js (+433/-0)
lib/lp/bugs/javascript/tests/test_subscription.html (+41/-0)
lib/lp/bugs/javascript/tests/test_subscription.js (+740/-0)
lib/lp/bugs/templates/bug-subscription-list.pt (+8/-4)
To merge this branch: bzr merge lp:~danilo/launchpad/bug728370-nondirect-subs
Reviewer Review Type Date Requested Status
Gary Poster (community) Approve
Review via email: mp+57293@code.launchpad.net

Commit message

[r=gary][bug=728370][incr] Provide infrastructure for gathering non-direct subscription information.

Description of the change

= Descriptions for non-direct subscriptions =

This introduces code to render appropriate messages based on the types of subscriptions you have for the 'unsubscribe-in-anger' story (which means, you are getting email from a certain bug, and want it to stop).

Atm, the branch only provides low-level JS code to get a subscription reason and variables to be (potentially) replaced in those reason strings, and doesn't tie it up with anything.

It is based on already landed code for bug 728370 to expose all the needed data to JS in LP.cache.bug_subscription_info, which we make direct use of.

== Implementation details ==

This is my first real TDD JS branch. This means that there was plenty of refactoring along the way. It is also incomplete in the sense that it doesn't really provide any value for the user. However, it is pretty big (1250 lines of diff) that I want it reviewed separately. Landing it will allow others to more easily collaborate on continuing work, and shouldn't affect anything otherwise.

Generally, we walk through LP.cache.subscription_info which is a container for several categories of subscriptions:

  - direct
  - as assignee
  - from duplicates
  - as project owner (implicit bug supervisor)

Each of those contains several lists of subscriptions by type:

  - personal
  - as team member
  - as team admin

(split because they will provide different 'unsubscribe actions').

This branch doesn't construct this data, it only uses it to return a list of subscriptions as records of the form:

  {
     reason: 'textual reason for a subscription with {vars} like this',
     vars: {
        team: ...,
        teams: ...,
        duplicate_bug: ...,
        duplicate_bugs: ...,
        pillar: ...,
     }
  }

Some of the bits in strings are obviously missing (like {pillar_type} variable) but I want to tackle that as we attempt to use them.

Some of the decisions about how we group/collate subscriptions are relatively arbitrary: we could have kept all of them as separate ones, but I followed what Gary has spent some time thinking through and used his constructed textual messages with only slight modifications.

== Tests ==

lib/lp/bugs/javascript/tests/test_subscription.html

== Demo and Q/A ==

Watch the JS console on:

  https://bugs.launchpad.dev/firefox/+bug/1/+subscriptions

It will log two objects: the actual LP.cache.bug_subscription_info and a list of all non-direct subscription descriptions.

To facilitate the demo, add a few subscriptions:

 - directly subscribe to bug 1
 - subscribe one of your teams you are a member of
 - subscribe one of your teams you are an admin of
 - make bugs 2 and 3 duplicates of bug 1
 - subscribe personally/as-team-member/as-team-admin to one of those
   duplicates
 - make yourself/your team the assignee on one or several bug tasks

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/javascript/subscription.js
  lib/lp/bugs/javascript/tests/test_subscription.html
  lib/lp/bugs/javascript/tests/test_subscription.js
  lib/lp/bugs/templates/bug-subscription-list.pt

To post a comment you must log in.
Revision history for this message
Gary Poster (gary) wrote :

This looks great, Danilo!

When reading the tests, I kept wanting to try and reduce the copy and paste elements of the test code by suggesting some helper functions. Maybe they exist, but when I compared the various "test_team_member_multiple" tests in the file as an example, they were not as similar as I expected. Therefore, I share the vague concern with you in case you have any ideas, but I don't ask you to make any changes because I didn't see any good ones after a quick look.

I had a couple of very small items. I already brought up the fact that the "short (just-enough)" parts of your test suite descriptions caused me to be a bit confused, for little gain. No biggie. I also wondered about your switch/case indentation: I would have indented your case statements. Maybe you have a good reason for them to be the way they are. Case statements are used infrequently enough that I doubt we have a rule for them. If you like it the way it is, that's fine.

I was going to ask about how you were going to use your strings--using Y.substitute and Y.Escape.html and so on--but you beat me to the bunch by bringing up the question in another forum, so nevermind. :-)

Thank you!

Gary

Revision history for this message
Gary Poster (gary) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'lib/lp/bugs/javascript/subscription.js'
--- lib/lp/bugs/javascript/subscription.js 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/javascript/subscription.js 2011-04-13 06:31:37 +0000
@@ -0,0 +1,433 @@
1/* Copyright 2011 Canonical Ltd. This software is licensed under the
2 * GNU Affero General Public License version 3 (see the file LICENSE).
3 *
4 * Provide information and actions on all bug subscriptions a person holds.
5 *
6 * @module bugs
7 * @submodule subscription
8 */
9
10YUI.add('lp.bugs.subscription', function(Y) {
11
12var namespace = Y.namespace('lp.bugs.subscription');
13
14/**
15 * These are the descriptions strings of what might be the cause of you
16 * getting an email.
17 */
18
19var _BECAUSE_YOU_ARE = 'You receive emails about this bug because you are ';
20
21/**
22 * Store complete subscription 'reasons' for easier overriding and testing.
23 *
24 * Other 'reasons' are added to the object as required string components
25 * are defined.
26 */
27var reasons = {
28 NOT_SUBSCRIBED: "You are not subscribed to this bug.",
29 MUTED_SUBSCRIPTION: "You have muted all email from this bug."
30};
31namespace._reasons = reasons;
32
33/* These are components for team participation. */
34var _OF_TEAM = 'of the team {team}. That team is ';
35var _OF_TEAMS = 'of the teams {teams}. Those teams are ';
36var _BECAUSE_TEAM_IS = _BECAUSE_YOU_ARE + 'a member ' + _OF_TEAM;
37var _ADMIN_BECAUSE_TEAM_IS = (
38 _BECAUSE_YOU_ARE + 'a member and administrator ' + _OF_TEAM);
39var _BECAUSE_TEAMS_ARE = _BECAUSE_YOU_ARE + 'a member ' + _OF_TEAMS;
40var _ADMIN_BECAUSE_TEAMS_ARE = (
41 _BECAUSE_YOU_ARE + 'a member and administrator ' + _OF_TEAMS);
42
43/* These are the assignment variations. */
44var _ASSIGNED = 'assigned to work on it.';
45/* These are the actual strings to use. */
46Y.mix(reasons, {
47 YOU_ASSIGNED: _BECAUSE_YOU_ARE + _ASSIGNED,
48 TEAM_ASSIGNED: _BECAUSE_TEAM_IS + _ASSIGNED,
49 ADMIN_TEAM_ASSIGNED: _ADMIN_BECAUSE_TEAM_IS + _ASSIGNED,
50 TEAMS_ASSIGNED: _BECAUSE_TEAMS_ARE + _ASSIGNED,
51 ADMIN_TEAMS_ASSIGNED: _ADMIN_BECAUSE_TEAMS_ARE + _ASSIGNED
52});
53
54/* These are the direct subscription variations. */
55var _SUBSCRIBED = 'directly subscribed to it.';
56var _MAY_HAVE_BEEN_CREATED = ' This subscription may have been created ';
57var _YOU_SUBSCRIBED = _BECAUSE_YOU_ARE + _SUBSCRIBED;
58
59/* Now these are the actual options we use. */
60Y.mix(reasons, {
61 YOU_SUBSCRIBED: _YOU_SUBSCRIBED,
62 YOU_REPORTED: (_YOU_SUBSCRIBED + _MAY_HAVE_BEEN_CREATED +
63 'when you reported the bug.'),
64 YOU_SUBSCRIBED_BUG_SUPERVISOR: (
65 _YOU_SUBSCRIBED + _MAY_HAVE_BEEN_CREATED +
66 'because the bug was private and you are a bug supervisor.'),
67 YOU_SUBSCRIBED_SECURITY_CONTACT: (
68 _YOU_SUBSCRIBED + _MAY_HAVE_BEEN_CREATED +
69 'because the bug was security related and you are ' +
70 'a security contact.'),
71 TEAM_SUBSCRIBED: _BECAUSE_TEAM_IS + _SUBSCRIBED,
72 ADMIN_TEAM_SUBSCRIBED: _ADMIN_BECAUSE_TEAM_IS + _SUBSCRIBED,
73 TEAMS_SUBSCRIBED: _BECAUSE_TEAMS_ARE + _SUBSCRIBED,
74 ADMIN_TEAMS_SUBSCRIBED: _ADMIN_BECAUSE_TEAMS_ARE + _SUBSCRIBED
75});
76
77/* These are the duplicate bug variations. */
78var _SUBSCRIBED_TO_DUPLICATE = (
79 'a direct subscriber to bug {duplicate_bug}, which is marked as a ' +
80 'duplicate of this bug, {bug_id}');
81var _SUBSCRIBED_TO_DUPLICATES = (
82 'a direct subscriber to bugs {duplicate_bugs}, which are marked as ' +
83 'duplicates of this bug, {bug_id}');
84/* These are the actual strings to use. */
85Y.mix(reasons, {
86 YOU_SUBSCRIBED_TO_DUPLICATE: _BECAUSE_YOU_ARE + _SUBSCRIBED_TO_DUPLICATE,
87 YOU_SUBSCRIBED_TO_DUPLICATES: (
88 _BECAUSE_YOU_ARE + _SUBSCRIBED_TO_DUPLICATES),
89 TEAM_SUBSCRIBED_TO_DUPLICATE: _BECAUSE_TEAM_IS + _SUBSCRIBED_TO_DUPLICATE,
90 TEAM_SUBSCRIBED_TO_DUPLICATES: (
91 _BECAUSE_TEAM_IS + _SUBSCRIBED_TO_DUPLICATES),
92 ADMIN_TEAM_SUBSCRIBED_TO_DUPLICATE: (
93 _ADMIN_BECAUSE_TEAM_IS + _SUBSCRIBED_TO_DUPLICATE),
94 ADMIN_TEAM_SUBSCRIBED_TO_DUPLICATES: (
95 _ADMIN_BECAUSE_TEAM_IS + _SUBSCRIBED_TO_DUPLICATES),
96});
97
98/* These are the owner variations. */
99var _OWNER = (
100 "the owner of the {pillar_type} " +
101 "{pillar}, which has no bug supervisor.");
102/* These are the actual strings to use. */
103Y.mix(reasons, {
104 YOU_OWNER: _BECAUSE_YOU_ARE + _OWNER,
105 TEAM_OWNER: _BECAUSE_TEAM_IS + _OWNER,
106 ADMIN_TEAM_OWNER: _ADMIN_BECAUSE_TEAM_IS + _OWNER,
107});
108
109
110/**
111 * Return appropriate object based on the number.
112 *
113 * @method choose_by_number.
114 * @param {Integer} number Number used in the string.
115 * @param {Object} singular Object to return when number == 1.
116 * @param {Object} plural Object to return when number != 1.
117 */
118function choose_by_number(number, singular, plural) {
119 if (number == 1) {
120 return singular;
121 } else {
122 return plural;
123 }
124}
125namespace._choose_by_number = choose_by_number;
126
127/**
128 * Replaces textual references in `info` with actual objects from `cache`.
129 *
130 * This assumes that object references are specified with strings
131 * starting with 'subscription-cache-reference', and are direct keys
132 * for objects in `cache`.
133 *
134 * @param {Object} info Object to recursively look for references through.
135 * @param {Object} cache Cache containing the objects indexed by their
136 * references.
137 */
138function replace_textual_references(info, cache) {
139 for (var key in info) {
140 switch (typeof info[key]){
141 case "object":
142 replace_textual_references(info[key], cache);
143 break;
144 case "string":
145 var ref_string = "subscription-cache-reference-";
146 if (info[key].substring(0, ref_string.length) == ref_string) {
147 info[key] = cache[info[key]];
148 }
149 break;
150 default: break;
151 }
152 }
153}
154namespace._replace_textual_references = replace_textual_references;
155
156/**
157 * ObjectLink class to unify link elements for better consistency.
158 * Needed because some objects expose `title`, others expose `display_name`.
159 */
160ObjectLink = function(self, title, url) {
161 return {
162 self: self,
163 title: title,
164 url: url
165 };
166}
167
168/**
169 * Convert a context object to a { title, url } object for use in web pages.
170 * Uses `display_name` and `web_link` attributes.
171 * Additionally, accepts a string as well and returns it unmodified.
172 */
173function get_link_data(context) {
174 // For testing, we take strings as well.
175 if (typeof(context) == 'string') {
176 return context;
177 } else {
178 return ObjectLink(context, context.display_name, context.web_link);
179 }
180}
181
182/**
183 * Convert a bug object to a { title, url } object for use in web pages.
184 * Uses `id` and `web_link` attributes.
185 * Additionally, accepts a string as well and returns it unmodified.
186 */
187function get_bug_link_data(bug) {
188 // For testing, we take strings as well.
189 if (typeof(bug) == 'string') {
190 return bug;
191 } else {
192 return ObjectLink(bug, 'bug #' + bug.id.toString(), bug.web_link);
193 }
194}
195
196/**
197 * Gather all team subscriptions and sort them by the role: member/admin.
198 * Returns up to 2 different subscription records, one for all teams
199 * a person is a member of, and another for all teams a person is
200 * an admin for.
201 * With one team in a subscription, variable `team` is set, and with more
202 * than one, variable `teams` is set containing all the teams.
203 */
204function gather_subscriptions_by_role(
205 category, team_singular, team_plural,
206 admin_team_singular, admin_team_plural) {
207 var subscriptions = [];
208 if (category.as_team_member.length > 0) {
209 var teams = [];
210 for (var index in category.as_team_member) {
211 var team_subscription = category.as_team_member[index];
212 teams.push(get_link_data(team_subscription.principal));
213 }
214 var sub = choose_by_number(
215 category.as_team_member.length,
216 { reason: team_singular,
217 vars: {
218 team: teams[0] } },
219 { reason: team_plural,
220 vars: {
221 teams: teams } });
222 subscriptions.push(sub);
223 }
224
225 if (category.as_team_admin.length > 0) {
226 var teams = [];
227 for (var index in category.as_team_admin) {
228 var team_subscription = category.as_team_admin[index];
229 teams.push(get_link_data(team_subscription.principal));
230 }
231 var sub = choose_by_number(
232 category.as_team_admin.length,
233 { reason: admin_team_singular,
234 vars: {
235 team: teams[0] } },
236 { reason: admin_team_plural,
237 vars: {
238 teams: teams } });
239 subscriptions.push(sub);
240 }
241
242 return subscriptions;
243}
244
245/**
246 * Gather subscription information for assignee.
247 */
248function gather_subscriptions_as_assignee(category) {
249 var subscriptions = [];
250 var reasons = namespace._reasons;
251
252 if (category.personal.length > 0) {
253 subscriptions.push(
254 { reason: reasons.YOU_ASSIGNED,
255 vars: {} });
256 }
257
258 // We add all the team assignments grouped by roles in the team.
259 return subscriptions.concat(
260 gather_subscriptions_by_role(
261 category, reasons.TEAM_ASSIGNED, reasons.TEAMS_ASSIGNED,
262 reasons.ADMIN_TEAM_ASSIGNED, reasons.ADMIN_TEAMS_ASSIGNED));
263}
264namespace._gather_subscriptions_as_assignee =
265 gather_subscriptions_as_assignee;
266
267/**
268 * Gather subscription information for implicit bug supervisor.
269 */
270function gather_subscriptions_as_supervisor(category) {
271 var subscriptions = [];
272 var reasons = namespace._reasons;
273
274 for (var index in category.personal) {
275 var subscription = category.personal[index];
276 subscriptions.push({
277 reason: reasons.YOU_OWNER,
278 vars: {
279 pillar: get_link_data(subscription.pillar)
280 }
281 });
282 }
283
284 for (var index in category.as_team_member) {
285 var team_subscription = category.as_team_member[index];
286 subscriptions.push({
287 reason: reasons.TEAM_OWNER,
288 vars: {
289 team: get_link_data(team_subscription.principal),
290 pillar: get_link_data(team_subscription.pillar)
291 }
292 });
293 }
294
295 for (var index in category.as_team_admin) {
296 var team_subscription = category.as_team_admin[index];
297 subscriptions.push({
298 reason: reasons.ADMIN_TEAM_OWNER,
299 vars: {
300 team: get_link_data(team_subscription.principal),
301 pillar: get_link_data(team_subscription.pillar)
302 }
303 });
304 }
305
306 return subscriptions;
307}
308namespace._gather_subscriptions_as_supervisor =
309 gather_subscriptions_as_supervisor;
310
311function gather_dupe_subscriptions_by_team(team_subscriptions,
312 singular, plural) {
313 var subscriptions = [];
314
315 // Collated list of { team: ..., bugs: []} records.
316 var dupes_by_teams = [];
317 for (var index in team_subscriptions) {
318 var subscription = team_subscriptions[index];
319 // Find the existing team reference.
320 var added_bug = false;
321 for (var team_dupes_idx in dupes_by_teams) {
322 var team_dupes = dupes_by_teams[team_dupes_idx];
323 if (team_dupes.team == subscription.principal) {
324 team_dupes.bugs.push(get_bug_link_data(subscription.bug));
325 added_bug = true;
326 break;
327 }
328 }
329 if (!added_bug) {
330 dupes_by_teams.push({
331 team: subscription.principal,
332 bugs: [get_bug_link_data(subscription.bug)]
333 });
334 }
335 }
336 for (var team_dupes_idx in dupes_by_teams) {
337 var team_dupes = dupes_by_teams[team_dupes_idx];
338 var sub = choose_by_number(
339 team_dupes.bugs.length,
340 { reason: singular,
341 vars: { duplicate_bug: team_dupes.bugs[0],
342 team: get_link_data(team_dupes.team) }},
343 { reason: plural,
344 vars: { duplicate_bugs: team_dupes.bugs,
345 team: get_link_data(team_dupes.team) }});
346 subscriptions.push(sub);
347 }
348 return subscriptions;
349}
350
351/**
352 * Gather subscription information from duplicate bug subscriptions.
353 */
354function gather_subscriptions_from_duplicates(category) {
355 var subscriptions = [];
356 var reasons = namespace._reasons;
357
358 if (category.personal.length > 0) {
359 var dupes = [];
360 for (var index in category.personal) {
361 var subscription = category.personal[index];
362 dupes.push(
363 get_bug_link_data(subscription.bug));
364 }
365 var sub = choose_by_number(
366 dupes.length,
367 { reason: reasons.YOU_SUBSCRIBED_TO_DUPLICATE,
368 vars: { duplicate_bug: dupes[0] }},
369 { reason: reasons.YOU_SUBSCRIBED_TO_DUPLICATES,
370 vars: { duplicate_bugs: dupes }});
371 subscriptions.push(sub);
372 }
373
374 // Get subscriptions as team member, grouped by teams.
375 subscriptions = subscriptions.concat(
376 gather_dupe_subscriptions_by_team(
377 category.as_team_member,
378 reasons.TEAM_SUBSCRIBED_TO_DUPLICATE,
379 reasons.TEAM_SUBSCRIBED_TO_DUPLICATES));
380
381 // Get subscriptions as team admin, grouped by teams.
382 subscriptions = subscriptions.concat(
383 gather_dupe_subscriptions_by_team(
384 category.as_team_admin,
385 reasons.ADMIN_TEAM_SUBSCRIBED_TO_DUPLICATE,
386 reasons.ADMIN_TEAM_SUBSCRIBED_TO_DUPLICATES));
387
388 return subscriptions;
389}
390namespace._gather_subscriptions_from_duplicates =
391 gather_subscriptions_from_duplicates;
392
393/**
394 * Gather subscription information from direct team subscriptions.
395 */
396function gather_subscriptions_through_team(category) {
397 var reasons = namespace._reasons;
398 return gather_subscriptions_by_role(
399 category, reasons.TEAM_SUBSCRIBED, reasons.TEAMS_SUBSCRIBED,
400 reasons.ADMIN_TEAM_SUBSCRIBED, reasons.ADMIN_TEAMS_SUBSCRIBED);
401}
402namespace._gather_subscriptions_through_team =
403 gather_subscriptions_through_team;
404
405/**
406 * Gather all non-direct subscriptions into a list.
407 */
408function gather_nondirect_subscriptions(info) {
409 var subscriptions = [];
410
411 return subscriptions
412 .concat(gather_subscriptions_as_assignee(info.as_assignee))
413 .concat(gather_subscriptions_from_duplicates(info.from_duplicate))
414 .concat(gather_subscriptions_through_team(info.direct))
415 .concat(gather_subscriptions_as_supervisor(info.as_owner));
416
417}
418
419function get_subscription_reason(config) {
420 // Allow tests to pass subscription_info directly in.
421 var info = config.subscription_info || LP.cache.bug_subscription_info;
422 console.log(info);
423 replace_textual_references(info, LP.cache);
424
425 var subs = gather_nondirect_subscriptions(info);
426 console.log(subs);
427
428}
429namespace.get_subscription_reason = get_subscription_reason
430
431}, '0.1', {requires: [
432 'dom', 'node', 'substitute'
433]});
0434
=== added file 'lib/lp/bugs/javascript/tests/test_subscription.html'
--- lib/lp/bugs/javascript/tests/test_subscription.html 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/javascript/tests/test_subscription.html 2011-04-13 06:31:37 +0000
@@ -0,0 +1,41 @@
1<html>
2 <head>
3 <title>Bug subscriptions: descriptions and unsubscribe actions</title>
4
5 <!-- YUI 3.0 Setup -->
6 <script type="text/javascript"
7 src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
8 <script type="text/javascript"
9 src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
10 <link rel="stylesheet"
11 href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
12 <link rel="stylesheet"
13 href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
14 <link rel="stylesheet"
15 href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
16 <link rel="stylesheet"
17 href="../../../../canonical/launchpad/javascript/test.css" />
18
19 <script type="text/javascript"
20 src="../../../app/javascript/client.js"></script>
21
22 <!-- The module under test -->
23 <script type="text/javascript"
24 src="../subscription.js"></script>
25
26 <!-- The test suite -->
27 <script type="text/javascript"
28 src="test_subscription.js"></script>
29
30 <!-- Pretty up the sample html -->
31 <style type="text/css">
32 div#sample {margin:15px; width:200px; border:1px solid #999; padding:10px;}
33 </style>
34 </head>
35 <body class="yui3-skin-sam">
36 <!-- Example markup required by test suite -->
37
38 <!-- The test output -->
39 <div id="log"></div>
40 </body>
41</html>
042
=== added file 'lib/lp/bugs/javascript/tests/test_subscription.js'
--- lib/lp/bugs/javascript/tests/test_subscription.js 1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/javascript/tests/test_subscription.js 2011-04-13 06:31:37 +0000
@@ -0,0 +1,740 @@
1YUI({
2 base: '../../../../canonical/launchpad/icing/yui/',
3 filter: 'raw', combine: false, fetchCSS: false
4 }).use('test', 'console', 'lp.bugs.subscription', function(Y) {
5
6var suite = new Y.Test.Suite("lp.bugs.subscription Tests");
7var module = Y.lp.bugs.subscription;
8
9/**
10 * Test selection of the string by the number.
11 * We expect to receive a plural string for all numbers
12 * not equal to 1, and a singular string otherwise.
13 */
14suite.add(new Y.Test.Case({
15 name: 'Choose object by number',
16
17 test_singular: function() {
18 Y.Assert.areEqual(
19 'SINGULAR',
20 module._choose_by_number(1, 'SINGULAR', 'PLURAL'));
21 },
22
23 test_plural: function() {
24 Y.Assert.areEqual(
25 'PLURAL',
26 module._choose_by_number(5, 'SINGULAR', 'PLURAL'));
27 },
28
29 test_zero: function() {
30 Y.Assert.areEqual(
31 'PLURAL',
32 module._choose_by_number(0, 'SINGULAR', 'PLURAL'));
33 }
34}));
35
36/**
37 * Replacing references to cache objects with actual objects.
38 */
39suite.add(new Y.Test.Case({
40 name: 'Replacing references with real objects',
41
42 test_nothing: function() {
43 // When there are no references, nothing gets replaced.
44 var object = {
45 something: 'nothing'
46 };
47 var cache = {};
48 module._replace_textual_references(object, cache)
49 Y.Assert.areEqual('nothing', object.something);
50 },
51
52 test_simple: function() {
53 // With a simple reference, it gets substituted.
54 var object = {
55 something: 'subscription-cache-reference-1'
56 };
57 var cache = {
58 'subscription-cache-reference-1': 'OK'
59 };
60 module._replace_textual_references(object, cache);
61 Y.Assert.areEqual('OK', object.something);
62 },
63
64 test_multiple: function() {
65 // With multiple references, they all get substituted.0
66 var object = {
67 something: 'subscription-cache-reference-1',
68 other: 'subscription-cache-reference-2'
69 };
70 var cache = {
71 'subscription-cache-reference-1': 'OK 1',
72 'subscription-cache-reference-2': 'OK 2'
73 };
74 module._replace_textual_references(object, cache);
75 Y.Assert.areEqual('OK 1', object.something);
76 Y.Assert.areEqual('OK 2', object.other);
77 },
78
79 test_recursive: function() {
80 // Even references in nested objects get replaced.
81 var object = {
82 nested: {
83 something: 'subscription-cache-reference-1'
84 }
85 };
86 var cache = {
87 'subscription-cache-reference-1': 'OK'
88 };
89 module._replace_textual_references(object, cache);
90 Y.Assert.areEqual('OK', object.nested.something);
91 }
92}));
93
94
95/**
96 * Gather subscription records for all assignments.
97 */
98suite.add(new Y.Test.Case({
99 name: 'Gather assignment subscription information',
100
101 test_nothing: function() {
102 // When there are no subscriptions as assignee, returns empty list.
103 var mock_category = {
104 count: 0,
105 personal: [],
106 as_team_member: [],
107 as_team_admin: []
108 };
109 Y.ArrayAssert.itemsAreEqual(
110 [],
111 module._gather_subscriptions_as_assignee(mock_category));
112 },
113
114 test_personal: function() {
115 // When a person is directly the bug assignee, we get that
116 // subscription details returned.
117 var mock_category = {
118 count: 1,
119 personal: [{}],
120 as_team_member: [],
121 as_team_admin: []
122 };
123 var subs = module._gather_subscriptions_as_assignee(mock_category);
124 Y.Assert.areEqual(1, subs.length);
125 Y.Assert.areEqual(module._reasons.YOU_ASSIGNED, subs[0].reason);
126 },
127
128 test_team_member: function() {
129 // When a person is the bug assignee through team membership,
130 // we get that subscription details returned.
131 var mock_category = {
132 count: 1,
133 personal: [],
134 as_team_member: [{ principal: 'my team'}],
135 as_team_admin: []
136 };
137 var subs = module._gather_subscriptions_as_assignee(mock_category);
138 Y.Assert.areEqual(1, subs.length);
139 Y.Assert.areEqual(module._reasons.TEAM_ASSIGNED, subs[0].reason);
140 // And there is a 'team' variable containing the team object.
141 Y.Assert.areEqual('my team', subs[0].vars.team);
142 },
143
144 test_team_member_multiple: function() {
145 // If a person is a member of multiple teams are assigned to work
146 // on a single bug (eg. on different bug tasks) they get only one
147 // subscription returned.
148 var mock_category = {
149 count: 2,
150 personal: [],
151 as_team_member: [{ principal: 'team1'},
152 { principal: 'team2'}],
153 as_team_admin: []
154 };
155 var subs = module._gather_subscriptions_as_assignee(mock_category);
156 Y.Assert.areEqual(1, subs.length);
157 Y.Assert.areEqual(module._reasons.TEAMS_ASSIGNED, subs[0].reason);
158 // And there is a 'teams' variable containing all the team objects.
159 Y.ArrayAssert.itemsAreEqual(['team1', 'team2'],
160 subs[0].vars.teams);
161 },
162
163 test_team_admin: function() {
164 // When a person is the bug assignee through team membership,
165 // and a team admin at the same time, that subscription is returned.
166 var mock_category = {
167 count: 1,
168 personal: [],
169 as_team_member: [],
170 as_team_admin: [{ principal: 'my team' }],
171 };
172 var subs = module._gather_subscriptions_as_assignee(mock_category);
173 Y.Assert.areEqual(1, subs.length);
174 Y.Assert.areEqual(
175 module._reasons.ADMIN_TEAM_ASSIGNED, subs[0].reason);
176 // And there is a 'team' variable containing the team object.
177 Y.Assert.areEqual('my team', subs[0].vars.team);
178 },
179
180 test_team_admin_multiple: function() {
181 // If a person is a member of multiple teams are assigned to work
182 // on a single bug (eg. on different bug tasks) they get only one
183 // subscription returned.
184 var mock_category = {
185 count: 2,
186 personal: [],
187 as_team_member: [],
188 as_team_admin: [{ principal: 'team1'},
189 { principal: 'team2'}],
190 };
191 var subs = module._gather_subscriptions_as_assignee(mock_category);
192 Y.Assert.areEqual(1, subs.length);
193 Y.Assert.areEqual(
194 module._reasons.ADMIN_TEAMS_ASSIGNED, subs[0].reason);
195 // And there is a 'teams' variable containing all the team objects.
196 Y.ArrayAssert.itemsAreEqual(['team1', 'team2'],
197 subs[0].vars.teams);
198 },
199
200 test_combined: function() {
201 // Test that multiple assignments, even if they are in different
202 // categories, work properly.
203 var mock_category = {
204 count: 3,
205 personal: [{}],
206 as_team_member: [{ principal: 'users' }],
207 as_team_admin: [{ principal: 'admins' }],
208 };
209 var subs = module._gather_subscriptions_as_assignee(mock_category);
210 Y.Assert.areEqual(3, subs.length);
211 },
212
213 test_object_links: function() {
214 // Test that team assignments actually provide decent link data.
215 var mock_category = {
216 count: 1,
217 personal: [],
218 as_team_member: [
219 { principal: { display_name: 'My team',
220 web_link: 'http://link' } }],
221 as_team_admin: [],
222 };
223 var subs = module._gather_subscriptions_as_assignee(mock_category);
224 Y.Assert.areEqual('My team', subs[0].vars.team.title);
225 Y.Assert.areEqual('http://link', subs[0].vars.team.url);
226 },
227}));
228
229/**
230 * Gather subscription records for bug supervisor.
231 */
232suite.add(new Y.Test.Case({
233 name: 'Gather bug supervisor subscription information',
234
235 test_nothing: function() {
236 // When there are no subscriptions as bug supervisor,
237 // returns empty list.
238 var mock_category = {
239 count: 0,
240 personal: [],
241 as_team_member: [],
242 as_team_admin: []
243 };
244 Y.ArrayAssert.itemsAreEqual(
245 [],
246 module._gather_subscriptions_as_supervisor(mock_category));
247 },
248
249 test_personal: function() {
250 // Person is the implicit bug supervisor by being the owner
251 // of the project with no bug supervisor.
252 var mock_category = {
253 count: 1,
254 personal: [{pillar: 'project'}],
255 as_team_member: [],
256 as_team_admin: []
257 };
258 var subs = module._gather_subscriptions_as_supervisor(mock_category);
259 Y.Assert.areEqual(1, subs.length);
260 Y.Assert.areEqual(module._reasons.YOU_OWNER, subs[0].reason);
261 Y.Assert.areEqual('project', subs[0].vars.pillar);
262 },
263
264 test_personal_multiple: function() {
265 // Person is the implicit bug supervisor by being the owner
266 // of several projects (eg. multiple bug tasks) with no bug
267 // supervisor.
268 var mock_category = {
269 count: 2,
270 personal: [{pillar: 'project'}, {pillar: 'distro'}],
271 as_team_member: [],
272 as_team_admin: []
273 };
274 var subs = module._gather_subscriptions_as_supervisor(mock_category);
275 Y.Assert.areEqual(2, subs.length);
276 },
277
278 test_team_member: function() {
279 // Person is a member of the team which is the implicit
280 // bug supervisor.
281 var mock_category = {
282 count: 1,
283 personal: [],
284 as_team_member: [{ principal: 'my team',
285 pillar: 'project' }],
286 as_team_admin: []
287 };
288 var subs = module._gather_subscriptions_as_supervisor(mock_category);
289 Y.Assert.areEqual(1, subs.length);
290 Y.Assert.areEqual(module._reasons.TEAM_OWNER, subs[0].reason);
291 // And there is a 'team' variable containing the team object.
292 Y.Assert.areEqual('my team', subs[0].vars.team);
293 Y.Assert.areEqual('project', subs[0].vars.pillar);
294 },
295
296 test_team_member_multiple: function() {
297 // Person is a member of several teams which are implicit bug
298 // supervisors on multiple bugtasks, we get subscription
299 // records separately.
300 var mock_category = {
301 count: 2,
302 personal: [],
303 as_team_member: [{ principal: 'team1',
304 pillar: 'project' },
305 { principal: 'team2',
306 pillar: 'distro' }],
307 as_team_admin: []
308 };
309 var subs = module._gather_subscriptions_as_supervisor(mock_category);
310 Y.Assert.areEqual(2, subs.length);
311 },
312
313 test_team_admin: function() {
314 // Person is an admin of the team which is the implicit
315 // bug supervisor.
316 var mock_category = {
317 count: 1,
318 personal: [],
319 as_team_member: [],
320 as_team_admin: [{ principal: 'my team',
321 pillar: 'project' }],
322 };
323 var subs = module._gather_subscriptions_as_supervisor(mock_category);
324 Y.Assert.areEqual(1, subs.length);
325 Y.Assert.areEqual(
326 module._reasons.ADMIN_TEAM_OWNER, subs[0].reason);
327 // And there is a 'team' variable containing the team object.
328 Y.Assert.areEqual('my team', subs[0].vars.team);
329 Y.Assert.areEqual('project', subs[0].vars.pillar);
330 },
331
332 test_team_admin_multiple: function() {
333 // Person is an admin of several teams which are implicit bug
334 // supervisors on multiple bugtasks, we get subscription
335 // records separately.
336 var mock_category = {
337 count: 2,
338 personal: [],
339 as_team_member: [],
340 as_team_admin: [{ principal: 'team1',
341 pillar: 'project' },
342 { principal: 'team2',
343 pillar: 'distro' }]
344 };
345 var subs = module._gather_subscriptions_as_supervisor(mock_category);
346 Y.Assert.areEqual(2, subs.length);
347 },
348
349 test_combined: function() {
350 // Test that multiple implicit bug supervisor roles
351 // are all returned.
352 var mock_category = {
353 count: 3,
354 personal: [{pillar: 'project1'}],
355 as_team_member: [{ principal: 'users', pillar: 'project2' }],
356 as_team_admin: [{ principal: 'admins', pillar: 'distro' }],
357 };
358 var subs = module._gather_subscriptions_as_assignee(mock_category);
359 Y.Assert.areEqual(3, subs.length);
360 },
361
362 test_object_links: function() {
363 // Test that team-as-supervisor actually provide decent link data,
364 // along with pillars as well.
365 var mock_category = {
366 count: 1,
367 personal: [],
368 as_team_member: [{
369 principal: { display_name: 'My team',
370 web_link: 'http://link' },
371 pillar: { display_name: 'My project',
372 web_link: 'http://project/' }
373 }],
374 as_team_admin: [],
375 };
376 var subs = module._gather_subscriptions_as_supervisor(mock_category);
377 Y.Assert.areEqual('My team', subs[0].vars.team.title);
378 Y.Assert.areEqual('http://link', subs[0].vars.team.url);
379
380 Y.Assert.areEqual('My project', subs[0].vars.pillar.title);
381 Y.Assert.areEqual('http://project/', subs[0].vars.pillar.url);
382 },
383}));
384
385/**
386 * Gather subscription records for dupe bug subscriptions.
387 */
388suite.add(new Y.Test.Case({
389 name: 'Gather subscription information for duplicates',
390
391 test_nothing: function() {
392 // When there are no duplicate subscriptions, returns empty list.
393 var mock_category = {
394 count: 0,
395 personal: [],
396 as_team_member: [],
397 as_team_admin: []
398 };
399 Y.ArrayAssert.itemsAreEqual(
400 [],
401 module._gather_subscriptions_from_duplicates(mock_category));
402 },
403
404 test_personal: function() {
405 // A person is subscribed to a duplicate bug.
406 var mock_category = {
407 count: 1,
408 personal: [{bug: 'dupe bug'}],
409 as_team_member: [],
410 as_team_admin: []
411 };
412 var subs = module._gather_subscriptions_from_duplicates(
413 mock_category);
414 Y.Assert.areEqual(1, subs.length);
415 Y.Assert.areEqual(
416 module._reasons.YOU_SUBSCRIBED_TO_DUPLICATE, subs[0].reason);
417 Y.Assert.areEqual('dupe bug', subs[0].vars.duplicate_bug);
418 },
419
420 test_personal_multiple: function() {
421 // A person is subscribed to multiple duplicate bugs.
422 // They are returned together as one subscription record.
423 var mock_category = {
424 count: 2,
425 personal: [{bug: 'dupe1'}, {bug: 'dupe2'}],
426 as_team_member: [],
427 as_team_admin: []
428 };
429 var subs = module._gather_subscriptions_from_duplicates(
430 mock_category);
431 Y.Assert.areEqual(1, subs.length);
432 Y.Assert.areEqual(
433 module._reasons.YOU_SUBSCRIBED_TO_DUPLICATES, subs[0].reason);
434 Y.ArrayAssert.itemsAreEqual(
435 ['dupe1', 'dupe2'], subs[0].vars.duplicate_bugs);
436 },
437
438 test_team_member: function() {
439 // A person is a member of the team subscribed to a duplicate bug.
440 var mock_category = {
441 count: 1,
442 personal: [],
443 as_team_member: [{ principal: 'my team',
444 bug: 'dupe' }],
445 as_team_admin: []
446 };
447 var subs = module._gather_subscriptions_from_duplicates(
448 mock_category);
449 Y.Assert.areEqual(1, subs.length);
450 Y.Assert.areEqual(
451 module._reasons.TEAM_SUBSCRIBED_TO_DUPLICATE, subs[0].reason);
452 // And there is a 'team' variable containing the team object.
453 Y.Assert.areEqual('my team', subs[0].vars.team);
454 // And a 'duplicate_bug' variable pointing to the dupe.
455 Y.Assert.areEqual('dupe', subs[0].vars.duplicate_bug);
456 },
457
458 test_team_member_multiple_bugs: function() {
459 // A person is a member of the team subscribed to multiple
460 // duplicate bugs.
461 var mock_category = {
462 count: 1,
463 personal: [],
464 as_team_member: [{
465 principal: 'my team',
466 bug: 'dupe1'
467 }, {
468 principal: 'my team',
469 bug: 'dupe2'
470 }],
471 as_team_admin: []
472 };
473 var subs = module._gather_subscriptions_from_duplicates(
474 mock_category);
475 Y.Assert.areEqual(1, subs.length);
476 Y.Assert.areEqual(
477 module._reasons.TEAM_SUBSCRIBED_TO_DUPLICATES, subs[0].reason);
478 // And there is a 'team' variable containing the team object.
479 Y.Assert.areEqual('my team', subs[0].vars.team);
480 // And a 'duplicate_bugs' variable with the list of dupes.
481 Y.ArrayAssert.itemsAreEqual(
482 ['dupe1', 'dupe2'], subs[0].vars.duplicate_bugs);
483 },
484
485 test_team_member_multiple: function() {
486 // A person is a member of several teams subscribed to
487 // duplicate bugs.
488 var mock_category = {
489 count: 2,
490 personal: [],
491 as_team_member: [{ principal: 'team1',
492 bug: 'dupe1' },
493 { principal: 'team2',
494 bug: 'dupe1' }],
495 as_team_admin: []
496 };
497
498 // Result is two separate subscription records.
499 var subs = module._gather_subscriptions_from_duplicates(
500 mock_category);
501 Y.Assert.areEqual(2, subs.length);
502 },
503
504 test_team_admin: function() {
505 // A person is an admin of the team subscribed to a duplicate bug.
506 var mock_category = {
507 count: 1,
508 personal: [],
509 as_team_member: [],
510 as_team_admin: [{ principal: 'my team',
511 bug: 'dupe' }]
512 };
513 var subs = module._gather_subscriptions_from_duplicates(
514 mock_category);
515 Y.Assert.areEqual(1, subs.length);
516 Y.Assert.areEqual(
517 module._reasons.ADMIN_TEAM_SUBSCRIBED_TO_DUPLICATE,
518 subs[0].reason);
519 // And there is a 'team' variable containing the team object.
520 Y.Assert.areEqual('my team', subs[0].vars.team);
521 // And a 'duplicate_bug' variable pointing to the dupe.
522 Y.Assert.areEqual('dupe', subs[0].vars.duplicate_bug);
523 },
524
525 test_team_admin_multiple_bugs: function() {
526 // A person is an admin of the team subscribed to multiple
527 // duplicate bugs.
528 var mock_category = {
529 count: 1,
530 personal: [],
531 as_team_member: [],
532 as_team_admin: [{
533 principal: 'my team',
534 bug: 'dupe1'
535 }, {
536 principal: 'my team',
537 bug: 'dupe2'
538 }]
539 };
540 var subs = module._gather_subscriptions_from_duplicates(
541 mock_category);
542 Y.Assert.areEqual(1, subs.length);
543 Y.Assert.areEqual(
544 module._reasons.ADMIN_TEAM_SUBSCRIBED_TO_DUPLICATES,
545 subs[0].reason);
546 // And there is a 'team' variable containing the team object.
547 Y.Assert.areEqual('my team', subs[0].vars.team);
548 // And a 'duplicate_bugs' variable with the list of dupes.
549 Y.ArrayAssert.itemsAreEqual(
550 ['dupe1', 'dupe2'], subs[0].vars.duplicate_bugs);
551 },
552
553 test_team_admin_multiple: function() {
554 // A person is an admin of several teams subscribed to
555 // duplicate bugs.
556 var mock_category = {
557 count: 2,
558 personal: [],
559 as_team_member: [],
560 as_team_admin: [{ principal: 'team1',
561 bug: 'dupe1' },
562 { principal: 'team2',
563 bug: 'dupe1' }],
564 };
565
566 // Result is two separate subscription records.
567 var subs = module._gather_subscriptions_from_duplicates(
568 mock_category);
569 Y.Assert.areEqual(2, subs.length);
570 },
571
572 test_object_links: function() {
573 // Test that team dupe subscriptions actually provide decent
574 // link data, including duplicate bugs link data.
575 var mock_category = {
576 count: 1,
577 personal: [],
578 as_team_member: [{
579 principal: { display_name: 'My team',
580 web_link: 'http://link' },
581 bug: { id: 1,
582 web_link: 'http://launchpad/bug/1' }
583 }],
584 as_team_admin: [],
585 };
586 var subs = module._gather_subscriptions_from_duplicates(
587 mock_category);
588 Y.Assert.areEqual('My team', subs[0].vars.team.title);
589 Y.Assert.areEqual('http://link', subs[0].vars.team.url);
590
591 Y.Assert.areEqual('bug #1', subs[0].vars.duplicate_bug.title);
592 Y.Assert.areEqual(
593 'http://launchpad/bug/1', subs[0].vars.duplicate_bug.url);
594 },
595}));
596
597/**
598 * Gather subscription records for direct team subscriptions.
599 */
600suite.add(new Y.Test.Case({
601 name: 'Gather team subscription information',
602
603 test_nothing: function() {
604 // When there are no subscriptions through team, returns empty list.
605 var mock_category = {
606 count: 0,
607 personal: [],
608 as_team_member: [],
609 as_team_admin: []
610 };
611 Y.ArrayAssert.itemsAreEqual(
612 [],
613 module._gather_subscriptions_through_team(mock_category));
614 },
615
616 test_personal: function() {
617 // A personal subscription is not considered a team subscription.
618 var mock_category = {
619 count: 1,
620 personal: [{}],
621 as_team_member: [],
622 as_team_admin: []
623 };
624 Y.ArrayAssert.itemsAreEqual(
625 [],
626 module._gather_subscriptions_through_team(mock_category));
627 },
628
629 test_team_member: function() {
630 // Person is a member of the team subscribed to the bug.
631 var mock_category = {
632 count: 1,
633 personal: [],
634 as_team_member: [{ principal: 'my team'}],
635 as_team_admin: []
636 };
637 var subs = module._gather_subscriptions_through_team(mock_category);
638 Y.Assert.areEqual(1, subs.length);
639 Y.Assert.areEqual(module._reasons.TEAM_SUBSCRIBED, subs[0].reason);
640 // And there is a 'team' variable containing the team object.
641 Y.Assert.areEqual('my team', subs[0].vars.team);
642 },
643
644 test_team_member_multiple: function() {
645 // Person is a member of several teams subscribed to the bug.
646 var mock_category = {
647 count: 2,
648 personal: [],
649 as_team_member: [{ principal: 'team1'},
650 { principal: 'team2'}],
651 as_team_admin: []
652 };
653 var subs = module._gather_subscriptions_through_team(mock_category);
654 Y.Assert.areEqual(1, subs.length);
655 Y.Assert.areEqual(module._reasons.TEAMS_SUBSCRIBED, subs[0].reason);
656 // And there is a 'teams' variable containing all the team objects.
657 Y.ArrayAssert.itemsAreEqual(['team1', 'team2'],
658 subs[0].vars.teams);
659 },
660
661 test_team_admin: function() {
662 // Person is an admin of the team subscribed to the bug.
663 var mock_category = {
664 count: 1,
665 personal: [],
666 as_team_member: [],
667 as_team_admin: [{ principal: 'my team' }],
668 };
669 var subs = module._gather_subscriptions_through_team(mock_category);
670 Y.Assert.areEqual(1, subs.length);
671 Y.Assert.areEqual(
672 module._reasons.ADMIN_TEAM_SUBSCRIBED, subs[0].reason);
673 // And there is a 'team' variable containing the team object.
674 Y.Assert.areEqual('my team', subs[0].vars.team);
675 },
676
677 test_team_admin_multiple: function() {
678 // Person is an admin of the several teams subscribed to the bug.
679 var mock_category = {
680 count: 2,
681 personal: [],
682 as_team_member: [],
683 as_team_admin: [{ principal: 'team1'},
684 { principal: 'team2'}],
685 };
686 var subs = module._gather_subscriptions_through_team(mock_category);
687 Y.Assert.areEqual(1, subs.length);
688 Y.Assert.areEqual(
689 module._reasons.ADMIN_TEAMS_SUBSCRIBED, subs[0].reason);
690 // And there is a 'teams' variable containing all the team objects.
691 Y.ArrayAssert.itemsAreEqual(['team1', 'team2'],
692 subs[0].vars.teams);
693 },
694
695 test_combined: function() {
696 // Test that multiple subscriptions, even if they are in different
697 // categories, work properly, and that personal subscriptions are
698 // still ignored.
699 var mock_category = {
700 count: 3,
701 personal: [{}],
702 as_team_member: [{ principal: 'users' }],
703 as_team_admin: [{ principal: 'admins' }],
704 };
705 var subs = module._gather_subscriptions_through_team(mock_category);
706 Y.Assert.areEqual(2, subs.length);
707 },
708
709 test_object_links: function() {
710 // Test that team subscriptions actually provide decent link data.
711 var mock_category = {
712 count: 1,
713 personal: [],
714 as_team_member: [
715 { principal: { display_name: 'My team',
716 web_link: 'http://link' } }],
717 as_team_admin: [],
718 };
719 var subs = module._gather_subscriptions_through_team(mock_category);
720 Y.Assert.areEqual('My team', subs[0].vars.team.title);
721 Y.Assert.areEqual('http://link', subs[0].vars.team.url);
722 },
723}));
724
725var handle_complete = function(data) {
726 status_node = Y.Node.create(
727 '<p id="complete">Test status: complete</p>');
728 Y.one('body').appendChild(status_node);
729 };
730Y.Test.Runner.on('complete', handle_complete);
731Y.Test.Runner.add(suite);
732
733var console = new Y.Console({newestOnTop: false});
734console.render('#log');
735
736Y.on('domready', function() {
737 Y.Test.Runner.run();
738});
739});
740
0741
=== modified file 'lib/lp/bugs/templates/bug-subscription-list.pt'
--- lib/lp/bugs/templates/bug-subscription-list.pt 2011-04-07 21:31:29 +0000
+++ lib/lp/bugs/templates/bug-subscription-list.pt 2011-04-13 06:31:37 +0000
@@ -15,11 +15,15 @@
15 <script type="text/javascript"15 <script type="text/javascript"
16 tal:condition="16 tal:condition="
17 request/features/malone.advanced-structural-subscriptions.enabled">17 request/features/malone.advanced-structural-subscriptions.enabled">
18 LPS.use('lp.registry.structural_subscription', function(Y) {18 LPS.use('lp.registry.structural_subscription', 'lp.bugs.subscription',
19 var module = Y.lp.registry.structural_subscription;19 function(Y) {
20 var ss_module = Y.lp.registry.structural_subscription;
21 var info_module = Y.lp.bugs.subscription;
20 Y.on('domready', function() {22 Y.on('domready', function() {
21 module.setup_bug_subscriptions(23 ss_module.setup_bug_subscriptions(
22 {content_box: "#structural-subscription-content-box"})24 {content_box: "#structural-subscription-content-box"});
25 console.log(info_module.get_subscription_reason(
26 {description_box: "#description"}));
23 });27 });
24 });28 });
25 </script>29 </script>