7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
1 |
========================= |
2 |
IQuestionTarget interface |
|
3 |
========================= |
|
4 |
||
5 |
Launchpad includes an answer tracker. Questions are associated to objects |
|
6 |
implementing IQuestionTarget. |
|
7 |
||
8 |
# An IQuestionTarget object is made available to this test via the |
|
9 |
# 'target' variable by the test framework. It won't have any questions |
|
10 |
# associated with it at the start of the test. This is done because the |
|
11 |
# exact same test applies to all types of question targets: products, |
|
12 |
# distributions, and distribution source packages. |
|
13 |
# |
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
14 |
# Some parts of the IQuestionTarget interface are only accessible |
3691.235.2
by Francis J. Lacoste
Convert headers to moin style and comments in () to code comments. |
15 |
# to a registered user. |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
16 |
>>> login('no-priv@canonical.com') |
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
17 |
|
18 |
>>> from zope.component import getUtility |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
19 |
>>> from zope.interface.verify import verifyObject |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
20 |
>>> from lp.answers.interfaces.questiontarget import IQuestionTarget |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
21 |
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
22 |
>>> verifyObject(IQuestionTarget, target) |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
23 |
True |
24 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
25 |
|
26 |
New questions |
|
27 |
============= |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
28 |
|
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
29 |
Questions are always owned by a registered user. |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
30 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
31 |
>>> from lp.registry.interfaces.person import IPersonSet |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
32 |
>>> sample_person = getUtility(IPersonSet).getByEmail( |
33 |
... 'test@canonical.com') |
|
34 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
35 |
The newQuestion() method is used to create a question that will be associated |
36 |
with the target. It takes as parameters the question's owner, title and |
|
37 |
description. It also takes an optional parameter 'datecreated' which defaults |
|
38 |
to UTC_NOW. |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
39 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
40 |
# Initialize 'now' to a known value. |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
41 |
>>> from datetime import datetime, timedelta |
42 |
>>> from pytz import UTC |
|
43 |
>>> now = datetime.now(UTC) |
|
44 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
45 |
>>> question = target.newQuestion(sample_person, 'New question', |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
46 |
... 'Question description', datecreated=now) |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
47 |
>>> print question.title |
48 |
New question |
|
49 |
>>> print question.description |
|
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
50 |
Question description |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
51 |
>>> print question.owner.displayname |
52 |
Sample Person |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
53 |
>>> question.datecreated == now |
54 |
True |
|
55 |
>>> question.datelastquery == now |
|
56 |
True |
|
57 |
||
58 |
The created question starts in the 'Open' status and should have the owner |
|
59 |
subscribed to the question. |
|
60 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
61 |
>>> print question.status.title |
62 |
Open |
|
63 |
||
64 |
>>> for subscription in question.subscriptions: |
|
65 |
... print subscription.person.displayname |
|
66 |
Sample Person |
|
67 |
||
68 |
Questions can be written in any languages supported in Launchpad. The |
|
69 |
language of the request is available in the 'language' attribute. By default, |
|
70 |
requests are assumed to be written in English. |
|
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
71 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
72 |
>>> print question.language.code |
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
73 |
en |
74 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
75 |
It is possible to create questions in another language than English, by |
76 |
passing in the language that the question is written in. |
|
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
77 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
78 |
>>> from lp.services.worlddata.interfaces.language import ILanguageSet |
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
79 |
>>> french = getUtility(ILanguageSet)['fr'] |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
80 |
>>> question = target.newQuestion( |
81 |
... sample_person, "De l'aide S.V.P.", |
|
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
82 |
... "Pouvez-vous m'aider?", language=french, |
83 |
... datecreated=now + timedelta(seconds=30)) |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
84 |
>>> print question.language.code |
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
85 |
fr |
86 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
87 |
Anonymous users cannot use newQuestion(). |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
88 |
|
89 |
>>> login(ANONYMOUS) |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
90 |
>>> question = target.newQuestion( |
91 |
... sample_person, 'This will fail', 'Failed?') |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
92 |
Traceback (most recent call last): |
93 |
... |
|
94 |
Unauthorized... |
|
95 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
96 |
|
97 |
Retrieving questions |
|
98 |
==================== |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
99 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
100 |
The getQuestion() method is used to retrieve a question by id for a |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
101 |
particular target. |
102 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
103 |
>>> target.getQuestion(question.id) == question |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
104 |
True |
105 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
106 |
If you pass in a non-existent id or a question for a different target, the |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
107 |
method returns None. |
108 |
||
109 |
>>> print target.getQuestion(2) |
|
110 |
None |
|
111 |
>>> print target.getQuestion(12345) |
|
112 |
None |
|
113 |
||
114 |
||
115 |
Searching for questions |
|
116 |
======================= |
|
117 |
||
118 |
# Create new questions for the following tests. Odd questions will be |
|
119 |
# owned by Foo Bar and even questions will be owned by Sample Person. |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
120 |
>>> login('no-priv@canonical.com') |
3691.188.1
by Francis J. Lacoste
Add owner criteria to searchTickets |
121 |
>>> foo_bar = getUtility(IPersonSet).getByEmail('foo.bar@canonical.com') |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
122 |
>>> questions = [] |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
123 |
>>> for num in range(5): |
3691.188.1
by Francis J. Lacoste
Add owner criteria to searchTickets |
124 |
... if num % 2: |
125 |
... owner = foo_bar |
|
126 |
... else: |
|
127 |
... owner = sample_person |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
128 |
... description = ('Support request description%d.\n' |
129 |
... 'This request index is %d.') % (num, num) |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
130 |
... questions.append(target.newQuestion( |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
131 |
... owner, 'Question title%d' % num, description, |
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
132 |
... datecreated=now+timedelta(minutes=num+1))) |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
133 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
134 |
# For more variety, we will set the status of the last to INVALID and the |
135 |
# fourth one to ANSWERED. |
|
3691.197.104
by Francis J. Lacoste
- Protect setStatus by launchpad.Admin. |
136 |
>>> login('foo.bar@canonical.com') |
3691.197.16
by Francis J. Lacoste
- Add setStatus() and addComment() methods. |
137 |
>>> foo_bar = getUtility(IPersonSet).getByEmail('foo.bar@canonical.com') |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
138 |
>>> message = questions[-1].reject( |
139 |
... foo_bar, 'Invalid question.', datecreated=now+timedelta(hours=1)) |
|
140 |
>>> message = questions[3].giveAnswer( |
|
3691.235.4
by Francis J. Lacoste
Added needs_attention_from parameter to ITicketTarget.searchTickets(). |
141 |
... sample_person, 'This is your answer.', |
142 |
... datecreated=now+timedelta(hours=1)) |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
143 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
144 |
# Also add a reply from the owner on the first of these. |
3691.345.5
by Francis J. Lacoste
Add TicketSort.RECENT_OWNER_ACTIVITY. |
145 |
>>> login('test@canonical.com') |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
146 |
>>> message = questions[0].giveInfo( |
3691.345.5
by Francis J. Lacoste
Add TicketSort.RECENT_OWNER_ACTIVITY. |
147 |
... 'I think I forgot something.', datecreated=now+timedelta(hours=4)) |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
148 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
149 |
# Create another one that will also have the word 'new' in its |
150 |
# description. |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
151 |
>>> question = target.newQuestion(sample_person, 'Another question', |
152 |
... 'Another new question that is actually very new.', |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
153 |
... datecreated=now+timedelta(hours=1)) |
154 |
>>> login(ANONYMOUS) |
|
155 |
||
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
156 |
The searchQuestions() method is used to search for questions. |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
157 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
158 |
|
159 |
Search text |
|
160 |
----------- |
|
3691.235.3
by Francis J. Lacoste
Add section headers for searchTickets() parameters. |
161 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
162 |
The search_text parameter will select the questions that contain the |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
163 |
passed in text. The standard text searching algorithm is used; see |
164 |
../../../canonical/launchpad/doct/textsearching.txt. |
|
3691.235.3
by Francis J. Lacoste
Add section headers for searchTickets() parameters. |
165 |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
166 |
>>> for t in target.searchQuestions(search_text='new'): |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
167 |
... print t.title |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
168 |
New question |
169 |
Another question |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
170 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
171 |
The results are sorted by relevancy. In the last questions, 'New' appeared in |
172 |
the description which makes it less relevant than when the word appears in the |
|
173 |
title. |
|
174 |
||
175 |
||
176 |
Status |
|
177 |
------ |
|
178 |
||
179 |
The searchQuestions() method can also filter questions by status. |
|
180 |
||
12915.5.1
by Curtis Hovey
Rename questionenums.py to the new standard or enums.py |
181 |
>>> from lp.answers.enums import QuestionStatus |
3691.398.20
by Francis J. Lacoste
Rename all methods. |
182 |
>>> for t in target.searchQuestions(status=QuestionStatus.OPEN): |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
183 |
... print t.title |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
184 |
Another question |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
185 |
Question title2 |
186 |
Question title1 |
|
187 |
Question title0 |
|
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
188 |
De l'aide S.V.P. |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
189 |
New question |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
190 |
|
191 |
In this previous example, because there is no sort text, the |
|
192 |
default sort order is from newest to oldest. |
|
193 |
||
3691.398.20
by Francis J. Lacoste
Rename all methods. |
194 |
>>> for t in target.searchQuestions(status=QuestionStatus.INVALID): |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
195 |
... print t.title |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
196 |
Question title4 |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
197 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
198 |
You can pass in a list of statuses, and you can also use the search_text and |
199 |
status parameters at the same time. This will search OPEN and INVALID |
|
200 |
questions with the word 'index'. |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
201 |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
202 |
>>> for t in target.searchQuestions(search_text='request index', |
3691.398.17
by Francis J. Lacoste
Rename dbschemas. |
203 |
... status=(QuestionStatus.OPEN, QuestionStatus.INVALID)): |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
204 |
... print t.title |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
205 |
Question title4 |
206 |
Question title2 |
|
207 |
Question title1 |
|
208 |
Question title0 |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
209 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
210 |
|
211 |
Sorting |
|
212 |
------- |
|
213 |
||
214 |
You can control the sort order by passing one of the constants defined in |
|
215 |
QuestionSort. Previously, we saw the NEWEST_FIRST and RELEVANCY sort order. |
|
216 |
||
217 |
You can sort also from oldest to newest using the OLDEST_FIRST constant. |
|
218 |
||
12915.5.1
by Curtis Hovey
Rename questionenums.py to the new standard or enums.py |
219 |
>>> from lp.answers.enums import QuestionSort |
3691.398.20
by Francis J. Lacoste
Rename all methods. |
220 |
>>> for t in target.searchQuestions(search_text='new', |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
221 |
... sort=QuestionSort.OLDEST_FIRST): |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
222 |
... print t.title |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
223 |
New question |
224 |
Another question |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
225 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
226 |
You can sort by status (the status order is OPEN, NEEDSINFO, ANSWERED, SOLVED, |
227 |
EXPIRED, INVALID). This also sorts from newest to oldest as a secondary key. |
|
228 |
Here we use status=None to search for all statuses; by default INVALID and |
|
229 |
EXPIRED questions are excluded. |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
230 |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
231 |
>>> for t in target.searchQuestions(search_text='request index', |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
232 |
... status=None, |
233 |
... sort=QuestionSort.STATUS): |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
234 |
... print t.status.title, t.title |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
235 |
Open Question title2 |
236 |
Open Question title1 |
|
237 |
Open Question title0 |
|
238 |
Answered Question title3 |
|
239 |
Invalid Question title4 |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
240 |
|
241 |
If there is no search_text and the requested sort order is RELEVANCY, |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
242 |
the questions will be sorted NEWEST_FIRST. |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
243 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
244 |
# 'Question title4' is not shown in this case because it has INVALID as |
245 |
# its status. |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
246 |
>>> for t in target.searchQuestions(sort=QuestionSort.RELEVANCY): |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
247 |
... print t.title |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
248 |
Another question |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
249 |
Question title3 |
250 |
Question title2 |
|
251 |
Question title1 |
|
252 |
Question title0 |
|
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
253 |
De l'aide S.V.P. |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
254 |
New question |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
255 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
256 |
The RECENT_OWNER_ACTIVITY sort order sorts first questions which recently |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
257 |
received a new message by their owner. It effectively sorts descending on the |
258 |
datelastquery attribute. |
|
3691.345.5
by Francis J. Lacoste
Add TicketSort.RECENT_OWNER_ACTIVITY. |
259 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
260 |
# Question title0 sorts first because it has a message from its owner |
261 |
# after the others were created. |
|
262 |
>>> for t in target.searchQuestions( |
|
263 |
... sort=QuestionSort.RECENT_OWNER_ACTIVITY): |
|
3691.345.5
by Francis J. Lacoste
Add TicketSort.RECENT_OWNER_ACTIVITY. |
264 |
... print t.title |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
265 |
Question title0 |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
266 |
Another question |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
267 |
Question title3 |
268 |
Question title2 |
|
269 |
Question title1 |
|
3691.345.5
by Francis J. Lacoste
Add TicketSort.RECENT_OWNER_ACTIVITY. |
270 |
De l'aide S.V.P. |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
271 |
New question |
3691.345.5
by Francis J. Lacoste
Add TicketSort.RECENT_OWNER_ACTIVITY. |
272 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
273 |
|
274 |
Owner |
|
275 |
----- |
|
276 |
||
277 |
You can find question owned by a particular user by using the owner parameter. |
|
3691.188.1
by Francis J. Lacoste
Add owner criteria to searchTickets |
278 |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
279 |
>>> for t in target.searchQuestions(owner=foo_bar): |
3691.188.1
by Francis J. Lacoste
Add owner criteria to searchTickets |
280 |
... print t.title |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
281 |
Question title3 |
282 |
Question title1 |
|
3691.188.1
by Francis J. Lacoste
Add owner criteria to searchTickets |
283 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
284 |
|
285 |
Language |
|
286 |
--------- |
|
3691.235.17
by Francis J. Lacoste
Merge RF, resolving 5 conflicts. |
287 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
288 |
The language criteria can be used to select only questions written in a |
3691.258.8
by Francis J. Lacoste
Add test for language criteria to searchTickets(). |
289 |
particular language. |
290 |
||
291 |
>>> english = getUtility(ILanguageSet)['en'] |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
292 |
>>> for t in target.searchQuestions(language=french): |
3691.258.8
by Francis J. Lacoste
Add test for language criteria to searchTickets(). |
293 |
... print t.title |
294 |
De l'aide S.V.P. |
|
295 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
296 |
>>> for t in target.searchQuestions(language=(english, french)): |
3691.258.8
by Francis J. Lacoste
Add test for language criteria to searchTickets(). |
297 |
... print t.title |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
298 |
Another question |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
299 |
Question title3 |
300 |
Question title2 |
|
301 |
Question title1 |
|
302 |
Question title0 |
|
3691.258.8
by Francis J. Lacoste
Add test for language criteria to searchTickets(). |
303 |
De l'aide S.V.P. |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
304 |
New question |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
305 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
306 |
|
307 |
Questions needing attention |
|
308 |
--------------------------- |
|
309 |
||
310 |
You can search among the questions that need attention. A question needs the |
|
311 |
attention of a user if he owns it and if it is in the NEEDSINFO or ANSWERED |
|
312 |
state. Questions on which the user gave an answer or requested for more |
|
313 |
information, and that are back in the OPEN state, are also included. |
|
3691.235.4
by Francis J. Lacoste
Added needs_attention_from parameter to ITicketTarget.searchTickets(). |
314 |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
315 |
# One of Sample Person's question gets to need attention from Foo Bar. |
3691.235.4
by Francis J. Lacoste
Added needs_attention_from parameter to ITicketTarget.searchTickets(). |
316 |
>>> login('foo.bar@canonical.com') |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
317 |
>>> message = questions[0].requestInfo( |
3691.235.4
by Francis J. Lacoste
Added needs_attention_from parameter to ITicketTarget.searchTickets(). |
318 |
... foo_bar, 'Do you have a clue?', |
319 |
... datecreated=now+timedelta(hours=1)) |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
320 |
|
3691.235.4
by Francis J. Lacoste
Added needs_attention_from parameter to ITicketTarget.searchTickets(). |
321 |
>>> login('test@canonical.com') |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
322 |
>>> message = questions[0].giveInfo( |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
323 |
... 'I do, now please help me.', datecreated=now+timedelta(hours=2)) |
3691.235.4
by Francis J. Lacoste
Added needs_attention_from parameter to ITicketTarget.searchTickets(). |
324 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
325 |
# Another one of Foo Bar's questions needs attention. |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
326 |
>>> message = questions[1].requestInfo( |
3691.235.4
by Francis J. Lacoste
Added needs_attention_from parameter to ITicketTarget.searchTickets(). |
327 |
... sample_person, 'And you, do you have a clue?', |
328 |
... datecreated=now+timedelta(hours=1)) |
|
329 |
||
330 |
>>> login(ANONYMOUS) |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
331 |
>>> for t in target.searchQuestions(needs_attention_from=foo_bar): |
3691.235.4
by Francis J. Lacoste
Added needs_attention_from parameter to ITicketTarget.searchTickets(). |
332 |
... print t.status.title, t.title, t.owner.displayname |
3691.398.19
by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.) |
333 |
Answered Question title3 Foo Bar |
334 |
Needs information Question title1 Foo Bar |
|
335 |
Open Question title0 Sample Person |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
336 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
337 |
|
338 |
Unsupported language |
|
339 |
-------------------- |
|
4004.4.14
by Curtis Hovey
Revised code and added a test per review. I'm still not convinced that handling show_all_languages outside of a widget is right. |
340 |
|
341 |
The 'unsupported' criteria is used to select questions that are in a |
|
342 |
language that is not spoken by any of the Support Contacts. |
|
343 |
||
4004.4.22
by Curtis Hovey
Changed unsupported to a boolean value in QuestionTargetSearch. |
344 |
>>> for t in target.searchQuestions(unsupported=True): |
4004.4.14
by Curtis Hovey
Revised code and added a test per review. I'm still not convinced that handling show_all_languages outside of a widget is right. |
345 |
... print t.title |
346 |
De l'aide S.V.P. |
|
347 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
348 |
|
349 |
Finding similar questions |
|
350 |
========================= |
|
351 |
||
352 |
The method findSimilarQuestions() can be use to find questions similar to some |
|
353 |
target text. The questions don't have to contain all the words of the text. |
|
354 |
||
355 |
# This returns the same results as with the search 'new' because |
|
356 |
# all other words in the text are either common ('question', 'title') or |
|
357 |
# stop words ('with', 'a'). |
|
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
358 |
>>> for t in target.findSimilarQuestions('new questions with a title'): |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
359 |
... print t.title |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
360 |
New question |
361 |
Another question |
|
11177.1.5
by Robert Collins
Fix fallout in tests. |
362 |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
363 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
364 |
|
365 |
Answer contacts |
|
366 |
=============== |
|
367 |
||
368 |
Targets can have answer contacts. The list of answer contacts for a |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
369 |
target is available through the answer_contacts attribute. |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
370 |
|
3935.3.12
by Curtis Hovey
Restored ftests/questiontarget.txt after removing the new sampledata. |
371 |
>>> list(target.answer_contacts) |
372 |
[] |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
373 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
374 |
There is also a direct_answer_contacts which includes only the answer contacts |
375 |
registered explicitly on the question target. In general, this will be the |
|
376 |
same as the answer_contacts attribute, but some IQuestionTarget |
|
377 |
implementations may inherit answer contacts from other contexts. In these |
|
378 |
cases, the direct_answer_contacts attribute would only contain the answer |
|
379 |
contacts defined in the current IQuestionTarget context. |
|
3691.243.4
by Francis J. Lacoste
Add registered_support_contacts attribute. |
380 |
|
3935.3.12
by Curtis Hovey
Restored ftests/questiontarget.txt after removing the new sampledata. |
381 |
>>> list(target.direct_answer_contacts) |
382 |
[] |
|
3691.243.4
by Francis J. Lacoste
Add registered_support_contacts attribute. |
383 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
384 |
You add an answer contact by using the addAnswerContact() method. This |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
385 |
is only available to registered users. |
386 |
||
387 |
>>> name18 = getUtility(IPersonSet).getByName('name18') |
|
12959.4.21
by Curtis Hovey
Alway pass the subscribed_by argument to addAnswerContact. |
388 |
>>> target.addAnswerContact(name18, name18) |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
389 |
Traceback (most recent call last): |
390 |
... |
|
391 |
Unauthorized... |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
392 |
|
393 |
This method returns True when the contact was added the list and False when it |
|
394 |
was already on the list. |
|
395 |
||
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
396 |
>>> login('no-priv@canonical.com') |
12959.4.21
by Curtis Hovey
Alway pass the subscribed_by argument to addAnswerContact. |
397 |
>>> target.addAnswerContact(name18, name18) |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
398 |
True |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
399 |
>>> people = [p.name for p in target.answer_contacts] |
400 |
>>> len(people) |
|
401 |
1 |
|
402 |
>>> print people[0] |
|
403 |
name18 |
|
404 |
>>> people = [p.name for p in target.direct_answer_contacts] |
|
405 |
>>> len(people) |
|
406 |
1 |
|
407 |
>>> print people[0] |
|
408 |
name18 |
|
12959.4.21
by Curtis Hovey
Alway pass the subscribed_by argument to addAnswerContact. |
409 |
>>> target.addAnswerContact(name18, name18) |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
410 |
False |
411 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
412 |
An answer contact must have at least one language among his preferred |
413 |
languages. |
|
4215.2.15
by Curtis Hovey
Added English to Lp. Rvised tests; removing old rules and added new rule. Translation tests probably fail. This branch needs some cleaning too. |
414 |
|
415 |
>>> sample_person = getUtility(IPersonSet).getByName('name12') |
|
7354.1.3
by Guilherme Salgado
Second aproach works. |
416 |
>>> len(sample_person.languages) |
4215.2.15
by Curtis Hovey
Added English to Lp. Rvised tests; removing old rules and added new rule. Translation tests probably fail. This branch needs some cleaning too. |
417 |
0 |
12959.4.21
by Curtis Hovey
Alway pass the subscribed_by argument to addAnswerContact. |
418 |
>>> target.addAnswerContact(sample_person, sample_person) |
4215.2.15
by Curtis Hovey
Added English to Lp. Rvised tests; removing old rules and added new rule. Translation tests probably fail. This branch needs some cleaning too. |
419 |
Traceback (most recent call last): |
420 |
... |
|
12959.4.23
by Curtis Hovey
Always pass the subscribed_by argument to addAnswerContact. |
421 |
AddAnswerContactError: An answer contact must speak a language... |
4215.2.23
by Curtis Hovey
Removed trailing whitespace. |
422 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
423 |
Answer contacts can be removed by using the removeAnswerContact() method. |
424 |
Like its counterpart, it returns True when the answer contact was removed and |
|
425 |
False when the person wasn't on the answer contact list. |
|
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
426 |
|
12959.4.21
by Curtis Hovey
Alway pass the subscribed_by argument to addAnswerContact. |
427 |
>>> target.removeAnswerContact(name18, name18) |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
428 |
True |
3935.3.12
by Curtis Hovey
Restored ftests/questiontarget.txt after removing the new sampledata. |
429 |
>>> list(target.answer_contacts) |
430 |
[] |
|
431 |
>>> list(target.direct_answer_contacts) |
|
432 |
[] |
|
12959.4.21
by Curtis Hovey
Alway pass the subscribed_by argument to addAnswerContact. |
433 |
>>> target.removeAnswerContact(name18, name18) |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
434 |
False |
435 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
436 |
Only registered users can remove an answer contact. |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
437 |
|
438 |
>>> login(ANONYMOUS) |
|
12959.4.21
by Curtis Hovey
Alway pass the subscribed_by argument to addAnswerContact. |
439 |
>>> target.removeAnswerContact(name18, name18) |
3691.110.79
by Francis J. Lacoste
Merge RF, resolving conflicts |
440 |
Traceback (most recent call last): |
441 |
... |
|
442 |
Unauthorized... |
|
3691.255.8
by Guilherme Salgado
Implementation of ITicketTarget.getSupportedLanguages(), which returns the languages spoken by that object's support contacts |
443 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
444 |
|
445 |
Supported languages |
|
446 |
=================== |
|
3691.255.14
by Francis J. Lacoste
Made language parameter optional. |
447 |
|
3691.398.18
by Francis J. Lacoste
Rename interfaces. |
448 |
The supported languages for a given IQuestionTarget are given by |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
449 |
getSupportedLanguages(). The supported languages of a question target include |
450 |
all languages spoken by at least one of its answer contacts, with the |
|
451 |
exception of all English variations since English is the assumed language for |
|
452 |
support when there are no answer contacts. |
|
453 |
||
454 |
>>> codes = [lang.code for lang in target.getSupportedLanguages()] |
|
455 |
>>> len(codes) |
|
456 |
1 |
|
457 |
>>> print codes[0] |
|
458 |
en |
|
459 |
||
460 |
# Let's add some answer contacts which speak different languages. |
|
3691.255.8
by Guilherme Salgado
Implementation of ITicketTarget.getSupportedLanguages(), which returns the languages spoken by that object's support contacts |
461 |
>>> login('carlos@canonical.com') |
462 |
>>> carlos = getUtility(IPersonSet).getByName('carlos') |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
463 |
>>> for language in carlos.languages: |
464 |
... print language.code |
|
465 |
ca |
|
466 |
en |
|
467 |
es |
|
12959.4.21
by Curtis Hovey
Alway pass the subscribed_by argument to addAnswerContact. |
468 |
>>> target.addAnswerContact(carlos, carlos) |
4450.6.3
by Curtis Hovey
Reconciled the new English variant rule with the other question tests. |
469 |
True |
3691.255.8
by Guilherme Salgado
Implementation of ITicketTarget.getSupportedLanguages(), which returns the languages spoken by that object's support contacts |
470 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
471 |
While daf has en_GB as one of his preferred languages... |
3935.3.12
by Curtis Hovey
Restored ftests/questiontarget.txt after removing the new sampledata. |
472 |
|
4450.6.3
by Curtis Hovey
Reconciled the new English variant rule with the other question tests. |
473 |
>>> login('daf@canonical.com') |
474 |
>>> daf = getUtility(IPersonSet).getByName('daf') |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
475 |
>>> for language in daf.languages: |
476 |
... print language.code |
|
477 |
en_GB |
|
478 |
ja |
|
479 |
cy |
|
12959.4.21
by Curtis Hovey
Alway pass the subscribed_by argument to addAnswerContact. |
480 |
>>> target.addAnswerContact(daf, daf) |
4450.6.3
by Curtis Hovey
Reconciled the new English variant rule with the other question tests. |
481 |
True |
3691.255.8
by Guilherme Salgado
Implementation of ITicketTarget.getSupportedLanguages(), which returns the languages spoken by that object's support contacts |
482 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
483 |
...en_GB is not included in the target's supported languages, because all |
484 |
English variants are converted to English. |
|
485 |
||
486 |
>>> from operator import attrgetter |
|
487 |
>>> print ', '.join( |
|
488 |
... language.code |
|
489 |
... for language in sorted(target.getSupportedLanguages(), |
|
490 |
... key=attrgetter('code'))) |
|
491 |
ca, cy, en, es, ja |
|
492 |
||
493 |
||
494 |
Answer contacts for languages |
|
495 |
============================= |
|
496 |
||
497 |
getAnswerContactsForLanguage() method returns a list of answer contacts who |
|
498 |
support the specified language in their preferred languages. Daf is in the |
|
499 |
list because he speaks an English variant, which is treated as English. |
|
4215.2.12
by Curtis Hovey
Removed Answer Contact want_english approach. Tests are broken |
500 |
|
4215.2.1
by Curtis Hovey
Merged model changes from curtis/launchpad/81369. |
501 |
>>> spanish = getUtility(ILanguageSet)['es'] |
502 |
>>> answer_contacts = target.getAnswerContactsForLanguage(spanish) |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
503 |
>>> for person in answer_contacts: |
504 |
... print person.name |
|
505 |
carlos |
|
4215.2.12
by Curtis Hovey
Removed Answer Contact want_english approach. Tests are broken |
506 |
|
4215.2.1
by Curtis Hovey
Merged model changes from curtis/launchpad/81369. |
507 |
>>> answer_contacts = target.getAnswerContactsForLanguage(english) |
10650.1.1
by Aaron Bentley
Fix test failure due to ordering issue. |
508 |
>>> for person in sorted(answer_contacts, key=lambda person: person.name): |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
509 |
... print person.name |
510 |
carlos |
|
511 |
daf |
|
512 |
||
513 |
||
514 |
A question's languages |
|
515 |
====================== |
|
3691.258.15
by Francis J. Lacoste
Add ITicketTarget.ticket_languages. |
516 |
|
3691.398.20
by Francis J. Lacoste
Rename all methods. |
517 |
The getQuestionLanguages() method returns the set of languages used by all |
3691.398.21
by Francis J. Lacoste
Rename all attributes and variables. |
518 |
of the target's questions. |
3691.258.15
by Francis J. Lacoste
Add ITicketTarget.ticket_languages. |
519 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
520 |
>>> print ', '.join( |
521 |
... sorted(language.code |
|
522 |
... for language in target.getQuestionLanguages())) |
|
523 |
en, fr |
|
524 |
||
525 |
||
526 |
Creating questions from bugs |
|
527 |
============================ |
|
528 |
||
529 |
The target can create a question from a bug, and link that bug to the new |
|
530 |
question. The question's owner is the same as the bug's owner. The question |
|
531 |
title and description are taken from the bug. The comments on the bug are |
|
532 |
copied to the question. |
|
4755.1.3
by Curtis Hovey
Revised and expanded interface/doctests. UI is next. |
533 |
|
4755.1.48
by Curtis Hovey
Changes per review. Anonther massive restructuring. |
534 |
>>> from datetime import datetime |
10650.1.2
by Aaron Bentley
Fix lint error. |
535 |
>>> from lp.bugs.interfaces.bug import CreateBugParams |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
536 |
>>> from lp.registry.interfaces.product import IProductSet |
11716.1.12
by Curtis Hovey
Sorted imports in doctests. |
537 |
>>> from pytz import UTC |
4755.1.48
by Curtis Hovey
Changes per review. Anonther massive restructuring. |
538 |
|
539 |
>>> now = datetime.now(UTC) |
|
540 |
>>> target = getUtility(IProductSet)['jokosher'] |
|
4755.1.3
by Curtis Hovey
Revised and expanded interface/doctests. UI is next. |
541 |
>>> bug_params = CreateBugParams( |
542 |
... title="Print is broken", comment="blah blah blah", |
|
543 |
... owner=sample_person) |
|
4755.1.48
by Curtis Hovey
Changes per review. Anonther massive restructuring. |
544 |
>>> target_bug = target.createBug(bug_params) |
545 |
>>> bug_message = target_bug.newMessage( |
|
4755.1.13
by Curtis Hovey
Updated models. The event still needs defining. The view needes tough-love. |
546 |
... owner=sample_person, subject="Opps, my mistake", |
547 |
... content="This is really a question.") |
|
548 |
||
4755.1.48
by Curtis Hovey
Changes per review. Anonther massive restructuring. |
549 |
>>> target_question = target.createQuestionFromBug(target_bug) |
4755.1.13
by Curtis Hovey
Updated models. The event still needs defining. The view needes tough-love. |
550 |
|
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
551 |
>>> print target_question.owner.displayname |
552 |
Sample Person |
|
553 |
>>> print target_question.title |
|
554 |
Print is broken |
|
555 |
>>> print target_question.description |
|
556 |
blah blah blah |
|
4755.1.13
by Curtis Hovey
Updated models. The event still needs defining. The view needes tough-love. |
557 |
>>> question_message = target_question.messages[-1] |
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
558 |
>>> print question_message.text_contents |
559 |
This is really a question. |
|
560 |
||
561 |
>>> for bug_link in target_question.bug_links: |
|
562 |
... print bug_link.bug.title |
|
563 |
Print is broken |
|
564 |
>>> print target_question.messages[-1].text_contents |
|
565 |
This is really a question. |
|
566 |
||
567 |
The question's creation date is the same as the bug's creation date. The |
|
568 |
question's last response date has a current datetime stamp to indicate the |
|
569 |
question is active. The question janitor would otherwise mistake the |
|
570 |
questions made from old bugs as old questions and would expire them. |
|
4755.1.48
by Curtis Hovey
Changes per review. Anonther massive restructuring. |
571 |
|
572 |
>>> target_question.datecreated == target_bug.datecreated |
|
573 |
True |
|
4755.1.49
by Curtis Hovey
Changes per review. |
574 |
>>> target_question.datelastresponse > now |
4755.1.48
by Curtis Hovey
Changes per review. Anonther massive restructuring. |
575 |
True |
576 |
||
7675.518.2
by Barry Warsaw
Reformat questiontarget.txt to current doctest style. |
577 |
The question language is always English because all bugs in Launchpad are |
578 |
written in English. |
|
579 |
||
580 |
>>> print target_question.language.code |
|
581 |
en |