~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
= Link to a FAQ =

Even though similar questions are shown when a user creates a new
question, common questions still happen for a number of reasons.
The Answer Tracker can be used to manage common answers
(a.k.a. Frequently Asked Question - FAQ) which can be used to answer
a particular question.

== Fix up sample data ==

The sample data has question titles which perform poorly with the sample data's
answers in fulltext searching, using efficient tsearch2 queries; we are going
to overhaul the fulltext search implementation but in the interim less prose
permits better matching. See bug 612384.

    >>> from zope.component import getUtility
    >>> from lp.registry.interfaces.product import IProductSet
    >>> from lp.testing import login, logout
    >>> login('test@canonical.com')
    >>> firefox = getUtility(IProductSet)['firefox']
    >>> svg_question = firefox.getQuestion(2)
    >>> svg_question.title = 'SVG extension'
    >>> logout()


== Linking to a FAQ ==

Any logged in user can use the 'Link to a FAQ' action item to link
the question to an existing FAQ.

For example, No Privileges Person comes across a question about SVG
support in Firefox. That question has a well-known answer, so he clicks
on 'Link to a FAQ' to answer the question:

    # We use backslashreplace because the page title includes smart quotes.
    >>> from canonical.launchpad.helpers import backslashreplace
    >>> user_browser.open(
    ...     'http://answers.launchpad.dev/firefox/+question/2')
    >>> print backslashreplace(user_browser.title)
    Question #2 : ...

    >>> user_browser.getLink('Link to a FAQ').click()
    >>> print backslashreplace(user_browser.title)
    Is question #2 a FAQ...

This page lists the existing FAQs matching the question's title. In
that listing, the radio labels only contain the FAQ id. The FAQ title is
displayed in a link besides the label. The default selected FAQ is the
one currently associated to the question. In this particular case, since
no FAQ is associated to the question, the 'No existing FAQs are
relevant' option is selected.

    >>> def printFAQOptions(contents):
    ...     buttons =  find_main_content(contents).findAll(
    ...         'input', {'name': 'field.faq'})
    ...     for button in buttons:
    ...         label = extract_text(button.parent)
    ...         if button.get('checked', None):
    ...             radio = '(*)'
    ...         else:
    ...             radio = '( )'
    ...         if button['value']:
    ...             link = button.findNext('a').renderContents()
    ...         else:
    ...             link = ''
    ...         print radio, label, link
    >>> printFAQOptions(user_browser.contents)
    (*) No existing FAQs are relevant
    ( ) 9: How do I troubleshoot problems with extensions/themes?
    ( ) 8: How do I install Extensions?

    >>> print user_browser.getLink('How do I troubleshoot problems').url
    http://answers.launchpad.dev/firefox/+faq/9

The query used to find these results is displayed in the search field
under the radio widgets. That query defaults to the question's title.

    >>> search_field = user_browser.getControl(name='field.faq-query')
    >>> print search_field.value
    SVG extension

From the titles, it doesn't seem like one of these FAQs would be
appropriate. The user can modify the search query and hit the 'Search'
button to update the list of available choices:

    >>> search_field.value = 'SVG plugin'
    >>> user_browser.getControl('Search', index=0).click()

The page is updated with a new list of FAQs:

    >>> print user_browser.title
    Is question #2 a FAQ...
    >>> printFAQOptions(user_browser.contents)
    (*) No existing FAQs are relevant
    ( ) 10: How do I install plugins (Shockwave, QuickTime, etc.)?
    ( ) 7: How do I install Java?

The most relevant result seems like the good answer, so the user selects
it.

    >>> user_browser.getControl('10').selected = True

There is a 'Message' field that will be used to answer the question.
It is pre-filled, but he can change its value. The FAQ reference will
be appended to the message.

    >>> print user_browser.getControl('Message').value
    No Privileges Person suggests this article as an answer to your question:

He can then click 'Link to FAQ' to answer the question with the selected
FAQ. After clicking the button, the user is redirected to the question
page.

    >>> user_browser.getControl('Link to FAQ').click()
    >>> print user_browser.url
    http://answers.launchpad.dev/firefox/+question/2

He sees that the question's status was changed to 'Answered':

    >>> def print_question_status(browser):
    ...     print extract_text(
    ...         find_tag_by_id(browser.contents, 'question-status'))

    >>> print_question_status(user_browser)
    Status: Answered

A link to the FAQ appears under the question's description:

    >>> print extract_text(
    ...     find_tag_by_id(user_browser.contents, 'related-faq'))
    Related FAQ: How do I install plugins (Shockwave, QuickTime, etc.)? ...
    >>> print user_browser.getLink('How do I install plugins').url
    http://answers.launchpad.dev/firefox/+faq/10

The answer message was added to the question's discussion:

    >>> print extract_text(find_tags_by_class(
    ...     user_browser.contents, 'boardCommentBody')[-1]).encode(
    ...     'ascii', 'backslashreplace')
    No Privileges Person suggests this article as an answer to your question:
    FAQ #10: \u201cHow do I install plugins...


== Modifying the FAQ ==

The link to the FAQ can be changed by using the same 'Link to a FAQ'
option. Continuing on the previous example, the user went on to read
the FAQ that he just linked and found that it doesn't really answer
the question. To correct the mistake, he uses the same 'Link to a FAQ'
action.

    >>> user_browser.getLink('Link to a FAQ').click()

The existing linked FAQ is selected and the other FAQs matching the
question's title are displayed:

    >>> printFAQOptions(user_browser.contents)
    ( ) No existing FAQs are relevant
    (*) 10: How do I install plugins (Shockwave, QuickTime, etc.)?
    ( ) 9: How do I troubleshoot problems with extensions/themes?
    ( ) 8: How do I install Extensions?

He changes the message and click 'Link to FAQ'.

    >>> user_browser.getControl('Message').value = (
    ...     "Sorry, this document doesn't really answer your question.")
    >>> user_browser.getControl('Link to FAQ').click()

But since, he forgot to change the link, the form is displayed again
with an error message.

    >>> print user_browser.url
    http://answers.launchpad.dev/firefox/+question/2/+linkfaq
    >>> for message in get_feedback_messages(user_browser.contents):
    ...     print message
    There is 1 error.
    You didn't modify the linked FAQ.

To remove the FAQ, the user selects the 'No existing...' option and
submit the form again.

    >>> user_browser.getControl('No existing FAQs').selected = True
    >>> user_browser.getControl('Link to FAQ').click()

The new message was added to the question:

    >>> print extract_text(find_tags_by_class(
    ...     user_browser.contents, 'boardCommentBody')[-1]).encode(
    ...     'ascii', 'backslashreplace')
    Sorry, this document doesn't really answer your question.

The link was also removed from the details portlet:

    >>> print extract_text(
    ...     find_tag_by_id(user_browser.contents, 'related-faq'))
    Related FAQ: None ...


== Creating a new FAQ ==

When no existing FAQs are relevant, it is possible to create a new FAQ
from the same 'Link to a FAQ' action. But this option is reserved to
users having 'moderation' privilege on the project (this includes
answer contacts and the project's owner).

Since No Privileges Person isn't an answer contact for the project nor
the project owner, he doesn't have the possibility to create a new FAQ.

    >>> user_browser.getLink('Create a FAQ')
    Traceback (most recent call last):
      ...
    LinkNotFoundError

    >>> user_browser.getLink('Link to a FAQ').click()
    >>> user_browser.getLink('create a new FAQ')
    Traceback (most recent call last):
      ...
    LinkNotFoundError

    >>> user_browser.open(
    ...     'http://answers.launchpad.dev/firefox/+question/2/+createfaq')
    Traceback (most recent call last):
      ...
    Unauthorized: ...

Sample Person who is the project owner does have that ability.

    >>> owner_browser = setupBrowser(auth='Basic test@canonical.com:test')
    >>> owner_browser.open(
    ...     'http://answers.launchpad.dev/firefox/+question/2')
    >>> owner_browser.getLink('Create a new FAQ')
    <Link text='Create a new FAQ' url='http://.../firefox/+question/2/+createfaq'>
    >>> owner_browser.getLink('Link to a FAQ').click()
    >>> owner_browser.getLink('create a new FAQ').click()
    >>> print owner_browser.url
    http://answers.launchpad.dev/firefox/+question/2/+createfaq
    >>> print owner_browser.title
    Create a FAQ for Mozilla...

The FAQ title and content are pre-filled with the target question. He
edits them to be more appropriate:

    >>> print owner_browser.getControl('Title').value
    SVG extension
    >>> owner_browser.getControl('Title').value = 'Displaying SVG in Firefox'

    >>> print owner_browser.getControl('Content').value
    Hi! I'm trying to learn about SVG but I can't get it to work at all in
    firefox. Maybe there is a plugin? Help! Thanks.

    >>> owner_browser.getControl('Content').value = (
    ...     'Upgrade your browser to Firefox 2.0.')

He can also enter keywords describing the FAQ:

    >>> owner_browser.getControl('Keywords').value = (
    ...     'scalable vector graphic')

There is a 'Message' field that will be used to answer the question.
It is pre-filled, but he can change its value:

    >>> print owner_browser.getControl(
    ...     'Additional comment for question #2').value
    Sample Person suggests this article as an answer to your question:

    >>> owner_browser.getControl(
    ...     'Additional comment for question #2').value = (
    ...     'Read the Fine Answer:')

After clicking the 'Create' button, the FAQ is created and the user is
returned to the question page.

    >>> owner_browser.getControl('Create and Link').click()
    >>> print owner_browser.url
    http://answers.launchpad.dev/firefox/+question/2

The answer message was added to the question's discussion:

    >>> print extract_text(find_tags_by_class(
    ...     owner_browser.contents, 'boardCommentBody')[-1]).encode(
    ...     'ascii', 'backslashreplace')
    Read the Fine Answer:
    FAQ...: \u201cDisplaying SVG in Firefox\u201d.

And the link to the created FAQ is displayed under the question's
description:

    >>> print extract_text(
    ...     find_tag_by_id(owner_browser.contents, 'related-faq'))
    Related FAQ: Displaying SVG in Firefox ...


== Viewing a FAQ ==

From a question page which has a related FAQ, the user can click on the
FAQ title to display the FAQ content.

    >>> owner_browser.getLink('Displaying SVG in Firefox').click()
    >>> print owner_browser.url
    http://answers.launchpad.dev/firefox/+faq/...
    >>> print backslashreplace(owner_browser.title)
    FAQ #12 : Questions : Mozilla Firefox

The FAQ keywords and content appears just below:

    >>> print extract_text(find_tag_by_id(
    ...     owner_browser.contents, 'faq-keywords'))
    Keywords: scalable vector graphic

    >>> print extract_text(find_tag_by_id(
    ...     owner_browser.contents, 'faq-content'))
    Upgrade your browser to Firefox 2.0.

The FAQ's original author and creation date appears in the header:

    >>> print extract_text(
    ...     find_tag_by_id(owner_browser.contents, 'registration'))
    Created by Sample Person on ...

A 'Related questions' portlet contains links to the question answered by
the FAQ:

    >>> print extract_text(find_portlet(
    ...     owner_browser.contents, 'Related questions'))
    Related questions
    #2 SVG extension

    >>> print owner_browser.getLink(
    ...     'SVG extension').url
    http://answers.launchpad.dev/firefox/+question/2


== Distribution and Source Packages ==

Questions asked about a distribution or distribution source package
can also be linked to FAQs.

    >>> user_browser.open(
    ...     'http://answers.launchpad.dev/ubuntu/+question/11')
    >>> print user_browser.title
    Question #11 : ...
    >>> user_browser.getLink('Link to a FAQ').click()
    >>> print user_browser.title
    Is question #11 a FAQ...

    >>> user_browser.open(
    ...     'http://answers.launchpad.dev/ubuntu/+source/mozilla-firefox'
    ...     '/+question/8')
    >>> print user_browser.title
    Question #8 : ...
    >>> user_browser.getLink('Link to a FAQ').click()
    >>> user_browser.title
    'Is question #8 a FAQ...


== Solved questions can be linked to a FAQ ==

When linking a solved question to a FAQ the action is treated as a
comment.

No Privileges Person sees a recently solved question that relates to a
FAQ. He decided to add it to the question to provide additional
information.

    >>> user_browser.open(
    ...     'http://answers.launchpad.dev/ubuntu/+source/mozilla-firefox/'
    ...     '+question/9')
    >>> details_portlet = find_portlet(
    ...     user_browser.contents, 'mozilla-firefox in ubuntu question #9')
    >>> print_question_status(user_browser)
    Status: Solved
    >>> user_browser.getLink('Link to a FAQ').click()

    >>> print user_browser.title
    Is question #9 a FAQ...
    >>> user_browser.getControl(name='field.faq-query').value = 'flash'
    >>> user_browser.getControl('Search', index=0).click()
    >>> user_browser.getControl('6').selected = True
    >>> user_browser.getControl('Message').value = "The FAQ mentions this:"
    >>> user_browser.getControl('Link to FAQ').click()

The question is still solved. No Privileges Person sees the FAQ was
added to the question, and his message was added to the question's
discussion.

    >>> print user_browser.title
    Question #9 : ...
    >>> print_question_status(user_browser)
    Status: Solved

    >>> print extract_text(
    ...     find_tag_by_id(user_browser.contents, 'related-faq'))
    Related FAQ:
    How can I play MP3/Divx/DVDs/Quicktime/Realmedia files ...

    >>> print extract_text(find_tags_by_class(
    ...     user_browser.contents, 'boardCommentBody')[-1]).encode(
    ...     'ascii', 'backslashreplace')
    The FAQ mentions this:
    FAQ #6: ...How can I play MP3/Divx/DVDs/Quicktime/Realmedia files...


== FAQs are links ==

You can respond to a question by pointing people to a FAQ. FAQs are
linkified as you would expect! You can use the "this is a FAQ" menu
item, as above:

    >>> user_browser.getLink('FAQ #6').url
    'http://answers.launchpad.dev/ubuntu/+faq/6'

Or you can just refer to FAQs in comments:

    >>> user_browser.getControl('Message').value = 'No, this is FAQ #2'
    >>> user_browser.getControl('Just Add a Comment').click()
    >>> user_browser.getLink("FAQ #2").url
    'http://answers.launchpad.dev/ubuntu/+faq/2'

The linkification also happens, incidentally, in bug comments and
anywhere else the email-to-html formatter is used. See
doc/displaying-paragraphs-of-text.txt for more details on this.