source: main/waeup.sirp/branches/henrik-bootstrap/src/waeup/sirp/accesscodes/browser.txt @ 10009

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

Backup local changes in branch (work in progress, not yet presentable).

File size: 13.8 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    ...
[7442]60    ...<h2>Access Code Batches</h2>
[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    ...
[7442]108    ...<h2>Access Code Batches</h2>
[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    ...
[7442]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    ...
[7442]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
177    >>> browser.getControl('Archive and Delete').click()
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>
[7372]286      <td>... - AC 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>
[7372]305      <td>... - AC initialized by Manager</td>
[6552]306    ...
307
308And we can search for text in history messages of access
309codes. Looking for the string ``AC initialized`` we get nearly all
310entries:
311
312    >>> browser.open('http://localhost/myuniversity/accesscodes/search')
313    >>> ctrl = browser.getControl(name='searchtype')
314    >>> ctrl.getControl(value='history').selected = True
315    >>> browser.getControl(name='searchterm').value = 'AC initialized'
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>
[7372]324      <td>... - AC 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
336    >>> browser.getControl(name='searchterm').value = 'AC initialized'
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 ...
[7442]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 ...
[7442]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 ...
[7442]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 ...
[7442]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.