source: main/waeup.kofa/trunk/src/waeup/kofa/doctests/accesscode_browser.txt @ 17782

Last change on this file since 17782 was 12946, checked in by Henrik Bettermann, 10 years ago

Rename doctests again.

File size: 14.1 KB
Line 
1UI Components for Access Codes
2******************************
3
4.. module:: waeup.kofa.accesscodes.browser
5
6Here we visit the access-code related parts of a Kofa site using
7a virtual browser.
8
9Preliminaries
10=============
11
12Before we can do anything, we have to create a university site:
13
14    >>> from zope.testbrowser.testing import Browser
15    >>> browser = Browser()
16    >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
17    >>> browser.handleErrors = False
18    >>> root = getRootFolder()
19
20    >>> from waeup.kofa.app import University
21    >>> u = University()
22    >>> root['myuniversity'] = u
23
24We set a new datacenter storage path:
25
26  >>> import os
27  >>> browser.open('http://localhost/myuniversity')
28  >>> browser.getLink('Data Center').click()
29  >>> browser.getLink('Edit settings').click()
30  >>> pathsetting = browser.getControl(name='newpath')
31
32  >>> cwd = os.getcwd()
33  >>> uploadpath = os.path.join(cwd, 'ac_testfiles')
34  >>> os.mkdir(uploadpath)
35  >>> pathsetting.value = uploadpath
36  >>> browser.getControl(name='save').click()
37
38We remove any existing 'accesscodes' dir from datacenter dir:
39
40  >>> import shutil
41  >>> if os.path.exists(os.path.join(uploadpath, 'accesscodes')):
42  ...   shutil.rmtree(os.path.join(uploadpath, 'accesscodes'))
43
44
45Access Code Management Screen
46=============================
47
48For users that have the right to manage access-code related stuff, the
49home page of a `University` instance provides a link to the
50access-code management screen. In the beginning, there are already
51three empty batches available which will be filled by online payments:
52
53    >>> browser.open('http://localhost/myuniversity')
54    >>> browser.getLink('Access Codes').click()
55    >>> print browser.contents
56    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
57    ...
58    ...<h1 class="kofa-content-label">Access Code Batches</h1>
59    ...
60    ... The following batches are available:
61    ...CLR...
62    ...HOS...
63    ...SFE...
64    ...
65
66Adding Batches
67==============
68
69We can add a batch of access-codes using a button displayed in the
70action bar:
71
72    >>> browser.getLink('Add Access Code Batch').click()
73
74The add screen shows a form where we have to enter a prefix, the
75number of access codes to be generated and the costs for each card.
76
77    >>> browser.getControl(name='form.prefix').value = 'APP'
78    >>> browser.getControl(name='form.entry_num').value = '5'
79    >>> browser.getControl(name='form.cost').value = '12.12'
80
81If we click 'cancel' afterwards, the whole process will be cancelled
82and we'll be redirected to the management screen:
83
84    >>> browser.getControl('Cancel').click()
85    >>> browser.url
86    'http://localhost/myuniversity/accesscodes'
87
88    >>> 'Batch creation cancelled' in browser.contents
89    True
90
91Now let's try again and this time we finish the procedure by clicking
92'Create batch' in the form:
93
94    >>> browser.getLink('Add Access Code Batch').click()
95    >>> browser.getControl(name='form.prefix').value = 'APP'
96    >>> browser.getControl(name='form.entry_num').value = '5'
97    >>> browser.getControl(name='form.cost').value = '12.12'
98    >>> browser.getControl('Create batch').click()
99
100We're also redirected to the management screen, with a notice about
101the freshly created batch:
102
103    >>> print browser.contents
104    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
105    ...
106    ...<h1 class="kofa-content-label">Access Code Batches</h1>
107    ...
108    ... The following batches are available:
109    ...APP
110    ...-
111    ...1
112    ...
113    ...5
114    ...
115    ...0
116    ...
117    ...12.12...
118    ...zope.mgr...
119    ...
120
121which means: there exists a batch named ``APP-1`` with 5 entries of
122which 0 have been devalidated, each one costs ``12.12`` and the batch
123was created by ``zope.mgr``.
124
125We create a second batch to see whether searching and related stuff
126works:
127
128    >>> browser.getLink('Add Access Code Batch').click()
129    >>> browser.getControl(name='form.prefix').value = 'APP'
130    >>> browser.getControl(name='form.entry_num').value = '5'
131    >>> browser.getControl(name='form.cost').value = '10.12'
132    >>> browser.getControl('Create batch').click()
133
134And a third one that can be deleted afterwards:
135
136    >>> browser.getLink('Add Access Code Batch').click()
137    >>> browser.getControl(name='form.prefix').value = 'BLA'
138    >>> browser.getControl(name='form.entry_num').value = '3'
139    >>> browser.getControl(name='form.cost').value = '19.12'
140    >>> browser.getControl('Create batch').click()
141
142
143Creating Archive Files
144======================
145
146Once a batch is created, we can archive it. To do so we have to tick
147the respective checkbox and click on 'Archive':
148
149    >>> ctrl = browser.getControl(name='batches')
150    >>> ctrl.getControl(value='APP-2').selected = True
151    >>> browser.getControl(name='archive').click()
152    >>> print browser.contents
153    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
154    ...
155    <div ...>Archived APP-2 (APP-2_archive-...-zope.mgr.csv)</div>
156    ...
157
158If we do not select a batch and try to archive or delete, the system
159will complain:
160
161    >>> browser.getControl(name='archive').click()
162    >>> print browser.contents
163    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
164    ...
165    <div ...>No batch selected.</div>
166    ...
167
168Deleting Batches
169================
170
171We can delete batches. They are automatically archived when doing so:
172
173    >>> ctrl = browser.getControl(name='batches')
174    >>> ctrl.getControl(value='BLA-1').selected = True
175    >>> browser.getControl('Archive and delete').click()
176    >>> print browser.contents
177    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
178    ...Archived BLA-1 (BLA-1_archive-...-zope.mgr.csv)...
179    ...Deleted batch BLA-1...
180    ...
181
182
183Reimporting Batches
184===================
185
186We can reimport batches using the log files written when a batch was
187created before. So one can reimport the freshly deleted BLA-1
188batch.
189
190To do so we must copy the logfile into the ``imports`` dir of
191accesscodes inside the university's datacenter storage. Otherwisae the
192list of importable files is empty:
193
194    >>> browser.getLink('Reimport Access Code Batch').click()
195    >>> print browser.contents
196    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
197    ...
198    ...No import batches available...
199    ...
200
201We can cancel that operation:
202
203    >>> browser.getControl('Cancel').click()
204
205We copy the ``BLA-1`` archive batch file over to the ``imports`` directory:
206
207    >>> ac_storage = os.path.join(uploadpath, 'accesscodes')
208    >>> logfile2 = os.path.join(ac_storage,
209    ...                         sorted(os.listdir(ac_storage))[-2])
210    >>> filename = os.path.basename(logfile2)
211    >>> filename
212    'BLA-1_archive...-zope.mgr.csv'
213
214    >>> import shutil
215    >>> import_path = os.path.join(ac_storage, 'imports')
216    >>> shutil.copy(logfile2, import_path)
217
218Now the file will be presented as import source:
219
220    >>> browser.getLink('Reimport Access Code Batch').click()
221    >>> filename in browser.contents
222    True
223
224If we do not tick a filename to import and click 'Reimport', we will
225be warned:
226
227    >>> browser.getControl('Reimport').click()
228    >>> print browser.contents
229    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
230    ...No file chosen. Action cancelled...
231
232Now let's really reimport the batch:
233
234    >>> browser.getLink('Reimport Access Code Batch').click()
235    >>> ctrl = browser.getControl(name='filenames')
236    >>> ctrl.getControl(value=filename).selected = True
237    >>> browser.getControl('Reimport').click()
238
239The batch does exist now again:
240
241    >>> print browser.contents
242    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
243    ...Successfully reimported: BLA-1_archive...-zope.mgr.csv...
244    ...
245
246If we try to reimport an existing batch, that won't work:
247
248    >>> browser.getLink('Reimport Access Code Batch').click()
249    >>> ctrl = browser.getControl(name='filenames')
250    >>> ctrl.getControl(value=filename).selected = True
251    >>> browser.getControl('Reimport').click()
252    >>> print browser.contents
253    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
254    ...This batch already exists: BLA-1_archive...-zope.mgr.csv...
255    ...
256
257Searching Access Codes
258======================
259
260We can search for access codes already created.
261
262First we pick some really existing access codes to look for:
263
264    >>> codes = getRootFolder()['myuniversity']['accesscodes']
265    >>> app_1_codes = codes[u'APP-1']
266    >>> app_2_codes = codes[u'APP-2']
267    >>> bla_1_codes = codes[u'BLA-1']
268
269    >>> browser.open('http://localhost/myuniversity/accesscodes/search')
270    >>> ctrl = browser.getControl(name='searchtype')
271    >>> ctrl.getControl(value='code').selected = True
272    >>> browser.getControl(name='searchterm').value = app_1_codes.keys()[0]
273    >>> browser.getControl(name='search').click()
274
275The first access code in the ``APP-1`` batch is displayed:
276
277    >>> print browser.contents
278    <!DOCTYPE html ...
279    ...
280      value="APP-1..." /></td>
281      <td>...</td>
282      <td>APP-1-...</td>
283      <td>initialized</td>
284      <td>... - initialized by Manager</td>
285    ...
286
287We can also search for batch serials (the number of an access code
288inside its batch). Looking for number ``1`` will display first access
289code of each batch ('APP-1', 'APP-2', and 'BLA-1')
290
291    >>> browser.open('http://localhost/myuniversity/accesscodes/search')
292    >>> ctrl = browser.getControl(name='searchtype')
293    >>> ctrl.getControl(value='batch_serial').selected = True
294    >>> browser.getControl(name='searchterm').value = '1'
295    >>> browser.getControl(name='search').click()
296    >>> print browser.contents
297    <!DOCTYPE html ...
298    ...
299      value="APP-1..." /></td>
300      <td>1</td>
301      <td>APP-1-...</td>
302      <td>initialized</td>
303      <td>... - initialized by Manager</td>
304    ...
305
306Searching for non-integer values does not result in an exception:
307
308    >>> ctrl = browser.getControl(name='searchtype')
309    >>> ctrl.getControl(value='batch_serial').selected = True
310    >>> browser.getControl(name='searchterm').value = 'xyz'
311    >>> browser.getControl(name='search').click()
312    >>> print browser.contents
313    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
314    ...
315
316And we can search for text in history messages of access
317codes. Looking for the string ``initialized`` we get nearly all
318entries:
319
320    >>> browser.open('http://localhost/myuniversity/accesscodes/search')
321    >>> ctrl = browser.getControl(name='searchtype')
322    >>> ctrl.getControl(value='history').selected = True
323    >>> browser.getControl(name='searchterm').value = 'initialized'
324    >>> browser.getControl(name='search').click()
325    >>> print browser.contents
326    <!DOCTYPE html ...
327    ...
328      value="APP-1-<10-DIGITS>" /></td>
329      <td>1</td>
330      <td>APP-1-<10-DIGITS></td>
331      <td>initialized</td>
332      <td>... - initialized by Manager</td>
333    ...
334
335Enabling and Disabling Found Access Codes
336=========================================
337
338If a search is successfull, we can enable or disable the found access
339codes:
340
341    >>> browser.open('http://localhost/myuniversity/accesscodes/search')
342    >>> ctrl = browser.getControl(name='searchtype')
343    >>> ctrl.getControl(value='history').selected = True
344    >>> browser.getControl(name='searchterm').value = 'initialized'
345    >>> browser.getControl(name='search').click()
346
347This lists all access codes. We now tick one to disable it and click
348on the appropriate button:
349
350    >>> entries = browser.getControl(name='entries')
351    >>> entries.controls[0].selected = True
352    >>> browser.getControl('Disable ACs').click()
353    >>> print browser.contents
354    <!DOCTYPE html ...
355    ...APP-1-<10-DIGITS> disabled.</div>
356    ...
357
358We cannot disable the same entry again:
359
360    >>> entries = browser.getControl(name='entries')
361    >>> entries.controls[0].selected = True
362    >>> browser.getControl('Disable ACs').click()
363    >>> print browser.contents
364    <!DOCTYPE html ...
365    <div ...>APP-1-<10-DIGITS>: Disable transition not allowed.</div>
366    ...
367
368But we can reenable the same entry:
369
370    >>> entries = browser.getControl(name='entries')
371    >>> entries.controls[0].selected = True
372    >>> browser.getControl('Enable ACs').click()
373    >>> print browser.contents
374    <!DOCTYPE html ...
375    ...APP-1-<10-DIGITS> (re-)enabled.</div>
376    ...
377
378Enabling already enabled items gives a warning:
379
380    >>> entries = browser.getControl(name='entries')
381    >>> entries.controls[0].selected = True
382    >>> browser.getControl('Enable ACs').click()
383    >>> print browser.contents
384    <!DOCTYPE html ...
385    <div ...>APP-1-<10-DIGITS>: Re-enable transition not allowed.</div>
386    ...
387
388Log- and Archive Files
389======================
390
391We store log- and archive-files inside the storage managed by the
392local datacenter. Access-code related files are placed inside an
393``accesscode`` subdir:
394
395    >>> ac_storage = os.path.join(uploadpath, 'accesscodes')
396
397Log files for access-code batches
398---------------------------------
399
400Whenever a batch is created, there is also a log file with all entries
401created:
402
403    >>> sorted(os.listdir(ac_storage))
404    ['APP-1-...-zope.mgr.csv', 'APP-2-...-zope.mgr.csv', ...]
405
406Each logfile name contains the prefix, batch number, date of creation
407and userid of creator.
408
409    >>> logfile1 = os.path.join(ac_storage,
410    ...                         sorted(os.listdir(ac_storage))[0])
411    >>> print open(logfile1, 'rb').read()
412    "serial","ac","cost"
413    "APP","1","12.12"
414    "0","APP-1-<10-DIGITS>"
415    "1","APP-1-<10-DIGITS>"
416    "2","APP-1-<10-DIGITS>"
417    "3","APP-1-<10-DIGITS>"
418    "4","APP-1-<10-DIGITS>"
419
420
421Archive files
422-------------
423
424We created an archive file above. An archive file name consists of the
425batch prefix, batch number, the string ``_archive``, creation datetime of
426the archive file and userid of batch creator:
427
428    >>> sorted(os.listdir(ac_storage))
429    [..., 'BLA-1_archive-...-zope.mgr.csv', 'imports']
430
431Archive files eventually also contain infos about invalidation dates
432and have a slightly different format therefore.
433
434    >>> archive_file = os.path.join(ac_storage,
435    ...                             sorted(os.listdir(ac_storage))[-2])
436    >>> print open(archive_file, 'rb').read()
437    "prefix","serial","ac","state","history","cost","owner"
438    "BLA","19.12","1","3"
439    "BLA","0","BLA-1-<10-DIGITS>","initialized","...","19.12",""
440    "BLA","1","BLA-1-<10-DIGITS>","initialized","...","19.12",""
441    "BLA","2","BLA-1-<10-DIGITS>","initialized","...","19.12",""
442
443Clean up:
444
445    >>> shutil.rmtree(uploadpath)
Note: See TracBrowser for help on using the repository browser.