UI Components for Access Codes¶
Here we visit the access-code related parts of a Kofa site using a virtual browser.
Preliminaries¶
Before we can do anything, we have to create a university site:
>>> from zope.testbrowser.testing import Browser
>>> browser = Browser()
>>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
>>> browser.handleErrors = False
>>> root = getRootFolder()
>>> from waeup.kofa.app import University
>>> u = University()
>>> root['myuniversity'] = u
We set a new datacenter storage path:
>>> import os
>>> browser.open('http://localhost/myuniversity')
>>> browser.getLink('Data Center').click()
>>> browser.getLink('Edit settings').click()
>>> pathsetting = browser.getControl(name='newpath')
>>> cwd = os.getcwd()
>>> uploadpath = os.path.join(cwd, 'ac_testfiles')
>>> os.mkdir(uploadpath)
>>> pathsetting.value = uploadpath
>>> browser.getControl(name='save').click()
We remove any existing ‘accesscodes’ dir from datacenter dir:
>>> import shutil
>>> if os.path.exists(os.path.join(uploadpath, 'accesscodes')):
... shutil.rmtree(os.path.join(uploadpath, 'accesscodes'))
Access Code Management Screen¶
For users that have the right to manage access-code related stuff, the home page of a University instance provides a link to the access-code management screen. In the beginning, there are already three empty batches available which will be filled by online payments:
>>> browser.open('http://localhost/myuniversity')
>>> browser.getLink('Access Codes').click()
>>> print browser.contents
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
...
...<h1 class="kofa-content-label">Access Code Batches</h1>
...
... The following batches are available:
...CLR...
...HOS...
...SFE...
...
Adding Batches¶
We can add a batch of access-codes using a button displayed in the action bar:
>>> browser.getLink('Add Access Code Batch').click()
The add screen shows a form where we have to enter a prefix, the number of access codes to be generated and the costs for each card.
>>> browser.getControl(name='form.prefix').value = 'APP'
>>> browser.getControl(name='form.entry_num').value = '5'
>>> browser.getControl(name='form.cost').value = '12.12'
If we click ‘cancel’ afterwards, the whole process will be cancelled and we’ll be redirected to the management screen:
>>> browser.getControl('Cancel').click()
>>> browser.url
'http://localhost/myuniversity/accesscodes'
>>> 'Batch creation cancelled' in browser.contents
True
Now let’s try again and this time we finish the procedure by clicking ‘Create batch’ in the form:
>>> browser.getLink('Add Access Code Batch').click()
>>> browser.getControl(name='form.prefix').value = 'APP'
>>> browser.getControl(name='form.entry_num').value = '5'
>>> browser.getControl(name='form.cost').value = '12.12'
>>> browser.getControl('Create batch').click()
We’re also redirected to the management screen, with a notice about the freshly created batch:
>>> print browser.contents
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
...
...<h1 class="kofa-content-label">Access Code Batches</h1>
...
... The following batches are available:
...APP
...-
...1
...
...5
...
...0
...
...12.12...
...zope.mgr...
...
which means: there exists a batch named APP-1
with 5 entries of
which 0 have been devalidated, each one costs 12.12
and the batch
was created by zope.mgr
.
We create a second batch to see whether searching and related stuff works:
>>> browser.getLink('Add Access Code Batch').click()
>>> browser.getControl(name='form.prefix').value = 'APP'
>>> browser.getControl(name='form.entry_num').value = '5'
>>> browser.getControl(name='form.cost').value = '10.12'
>>> browser.getControl('Create batch').click()
And a third one that can be deleted afterwards:
>>> browser.getLink('Add Access Code Batch').click()
>>> browser.getControl(name='form.prefix').value = 'BLA'
>>> browser.getControl(name='form.entry_num').value = '3'
>>> browser.getControl(name='form.cost').value = '19.12'
>>> browser.getControl('Create batch').click()
Creating Archive Files¶
Once a batch is created, we can archive it. To do so we have to tick the respective checkbox and click on ‘Archive’:
>>> ctrl = browser.getControl(name='batches')
>>> ctrl.getControl(value='APP-2').selected = True
>>> browser.getControl(name='archive').click()
>>> print browser.contents
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
...
<div ...>Archived APP-2 (APP-2_archive-...-zope.mgr.csv)</div>
...
If we do not select a batch and try to archive or delete, the system will complain:
>>> browser.getControl(name='archive').click()
>>> print browser.contents
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
...
<div ...>No batch selected.</div>
...
Deleting Batches¶
We can delete batches. They are automatically archived when doing so:
>>> ctrl = browser.getControl(name='batches')
>>> ctrl.getControl(value='BLA-1').selected = True
>>> browser.getControl('Archive and delete').click()
>>> print browser.contents
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
...Archived BLA-1 (BLA-1_archive-...-zope.mgr.csv)...
...Deleted batch BLA-1...
...
Reimporting Batches¶
We can reimport batches using the log files written when a batch was created before. So one can reimport the freshly deleted BLA-1 batch.
To do so we must copy the logfile into the imports
dir of
accesscodes inside the university’s datacenter storage. Otherwisae the
list of importable files is empty:
>>> browser.getLink('Reimport Access Code Batch').click()
>>> print browser.contents
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
...
...No import batches available...
...
We can cancel that operation:
>>> browser.getControl('Cancel').click()
We copy the BLA-1
archive batch file over to the imports
directory:
>>> ac_storage = os.path.join(uploadpath, 'accesscodes')
>>> logfile2 = os.path.join(ac_storage,
... sorted(os.listdir(ac_storage))[-2])
>>> filename = os.path.basename(logfile2)
>>> filename
'BLA-1_archive...-zope.mgr.csv'
>>> import shutil
>>> import_path = os.path.join(ac_storage, 'imports')
>>> shutil.copy(logfile2, import_path)
Now the file will be presented as import source:
>>> browser.getLink('Reimport Access Code Batch').click()
>>> filename in browser.contents
True
If we do not tick a filename to import and click ‘Reimport’, we will be warned:
>>> browser.getControl('Reimport').click()
>>> print browser.contents
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
...No file chosen. Action cancelled...
Now let’s really reimport the batch:
>>> browser.getLink('Reimport Access Code Batch').click()
>>> ctrl = browser.getControl(name='filenames')
>>> ctrl.getControl(value=filename).selected = True
>>> browser.getControl('Reimport').click()
The batch does exist now again:
>>> print browser.contents
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
...Successfully reimported: BLA-1_archive...-zope.mgr.csv...
...
If we try to reimport an existing batch, that won’t work:
>>> browser.getLink('Reimport Access Code Batch').click()
>>> ctrl = browser.getControl(name='filenames')
>>> ctrl.getControl(value=filename).selected = True
>>> browser.getControl('Reimport').click()
>>> print browser.contents
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
...This batch already exists: BLA-1_archive...-zope.mgr.csv...
...
Searching Access Codes¶
We can search for access codes already created.
First we pick some really existing access codes to look for:
>>> codes = getRootFolder()['myuniversity']['accesscodes']
>>> app_1_codes = codes[u'APP-1']
>>> app_2_codes = codes[u'APP-2']
>>> bla_1_codes = codes[u'BLA-1']
>>> browser.open('http://localhost/myuniversity/accesscodes/search')
>>> ctrl = browser.getControl(name='searchtype')
>>> ctrl.getControl(value='code').selected = True
>>> browser.getControl(name='searchterm').value = app_1_codes.keys()[0]
>>> browser.getControl(name='search').click()
The first access code in the APP-1
batch is displayed:
>>> print browser.contents
<!DOCTYPE html ...
...
value="APP-1..." /></td>
<td>...</td>
<td>APP-1-...</td>
<td>initialized</td>
<td>... - initialized by Manager</td>
...
We can also search for batch serials (the number of an access code
inside its batch). Looking for number 1
will display first access
code of each batch (‘APP-1’, ‘APP-2’, and ‘BLA-1’)
>>> browser.open('http://localhost/myuniversity/accesscodes/search')
>>> ctrl = browser.getControl(name='searchtype')
>>> ctrl.getControl(value='batch_serial').selected = True
>>> browser.getControl(name='searchterm').value = '1'
>>> browser.getControl(name='search').click()
>>> print browser.contents
<!DOCTYPE html ...
...
value="APP-1..." /></td>
<td>1</td>
<td>APP-1-...</td>
<td>initialized</td>
<td>... - initialized by Manager</td>
...
Searching for non-integer values does not result in an exception:
>>> ctrl = browser.getControl(name='searchtype')
>>> ctrl.getControl(value='batch_serial').selected = True
>>> browser.getControl(name='searchterm').value = 'xyz'
>>> browser.getControl(name='search').click()
>>> print browser.contents
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
...
And we can search for text in history messages of access
codes. Looking for the string initialized
we get nearly all
entries:
>>> browser.open('http://localhost/myuniversity/accesscodes/search')
>>> ctrl = browser.getControl(name='searchtype')
>>> ctrl.getControl(value='history').selected = True
>>> browser.getControl(name='searchterm').value = 'initialized'
>>> browser.getControl(name='search').click()
>>> print browser.contents
<!DOCTYPE html ...
...
value="APP-1-<10-DIGITS>" /></td>
<td>1</td>
<td>APP-1-<10-DIGITS></td>
<td>initialized</td>
<td>... - initialized by Manager</td>
...
Enabling and Disabling Found Access Codes¶
If a search is successfull, we can enable or disable the found access codes:
>>> browser.open('http://localhost/myuniversity/accesscodes/search')
>>> ctrl = browser.getControl(name='searchtype')
>>> ctrl.getControl(value='history').selected = True
>>> browser.getControl(name='searchterm').value = 'initialized'
>>> browser.getControl(name='search').click()
This lists all access codes. We now tick one to disable it and click on the appropriate button:
>>> entries = browser.getControl(name='entries')
>>> entries.controls[0].selected = True
>>> browser.getControl('Disable ACs').click()
>>> print browser.contents
<!DOCTYPE html ...
...APP-1-<10-DIGITS> disabled.</div>
...
We cannot disable the same entry again:
>>> entries = browser.getControl(name='entries')
>>> entries.controls[0].selected = True
>>> browser.getControl('Disable ACs').click()
>>> print browser.contents
<!DOCTYPE html ...
<div ...>APP-1-<10-DIGITS>: Disable transition not allowed.</div>
...
But we can reenable the same entry:
>>> entries = browser.getControl(name='entries')
>>> entries.controls[0].selected = True
>>> browser.getControl('Enable ACs').click()
>>> print browser.contents
<!DOCTYPE html ...
...APP-1-<10-DIGITS> (re-)enabled.</div>
...
Enabling already enabled items gives a warning:
>>> entries = browser.getControl(name='entries')
>>> entries.controls[0].selected = True
>>> browser.getControl('Enable ACs').click()
>>> print browser.contents
<!DOCTYPE html ...
<div ...>APP-1-<10-DIGITS>: Re-enable transition not allowed.</div>
...
Log- and Archive Files¶
We store log- and archive-files inside the storage managed by the
local datacenter. Access-code related files are placed inside an
accesscode
subdir:
>>> ac_storage = os.path.join(uploadpath, 'accesscodes')
Log files for access-code batches¶
Whenever a batch is created, there is also a log file with all entries created:
>>> sorted(os.listdir(ac_storage))
['APP-1-...-zope.mgr.csv', 'APP-2-...-zope.mgr.csv', ...]
Each logfile name contains the prefix, batch number, date of creation and userid of creator.
>>> logfile1 = os.path.join(ac_storage,
... sorted(os.listdir(ac_storage))[0])
>>> print open(logfile1, 'rb').read()
"serial","ac","cost"
"APP","1","12.12"
"0","APP-1-<10-DIGITS>"
"1","APP-1-<10-DIGITS>"
"2","APP-1-<10-DIGITS>"
"3","APP-1-<10-DIGITS>"
"4","APP-1-<10-DIGITS>"
Archive files¶
We created an archive file above. An archive file name consists of the
batch prefix, batch number, the string _archive
, creation datetime of
the archive file and userid of batch creator:
>>> sorted(os.listdir(ac_storage))
[..., 'BLA-1_archive-...-zope.mgr.csv', 'imports']
Archive files eventually also contain infos about invalidation dates and have a slightly different format therefore.
>>> archive_file = os.path.join(ac_storage,
... sorted(os.listdir(ac_storage))[-2])
>>> print open(archive_file, 'rb').read()
"prefix","serial","ac","state","history","cost","owner"
"BLA","19.12","1","3"
"BLA","0","BLA-1-<10-DIGITS>","initialized","...","19.12",""
"BLA","1","BLA-1-<10-DIGITS>","initialized","...","19.12",""
"BLA","2","BLA-1-<10-DIGITS>","initialized","...","19.12",""
Clean up:
>>> shutil.rmtree(uploadpath)