= 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 lp.services.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') >>> 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.