source: main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/browser.txt @ 7741

Last change on this file since 7741 was 7719, checked in by Henrik Bettermann, 13 years ago

Internationalize accessodes package.

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