Changeset 5132


Ignore:
Timestamp:
5 Apr 2010, 18:16:56 (15 years ago)
Author:
uli
Message:

Support reimport of AC batches.

Location:
main/waeup.sirp/trunk/src/waeup/sirp/accesscodes
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/accesscodes.py

    r5127 r5132  
    198198    grok.implements(IAccessCodeBatchContainer)
    199199
     200    def _getStoragePath(self):
     201        """Get the directory, where batch import files are stored.
     202        """
     203        site = grok.getSite()
     204        storagepath = site['datacenter'].storage
     205        ac_storage = os.path.join(storagepath, 'accesscodes')
     206        import_path = os.path.join(ac_storage, 'imports')
     207        if not os.path.exists(import_path):
     208            os.mkdir(import_path)
     209        return import_path
     210
    200211    def addBatch(self, batch):
    201212        """Add a batch.
     
    224235        return num
    225236
     237    def getImportFiles(self):
     238        """Return a generator with basenames of available import files.
     239        """
     240        path = self._getStoragePath()
     241        for filename in sorted(os.listdir(path)):
     242            yield filename
     243   
     244    def reimport(self, filename, creator=u'UNKNOWN'):
     245        """Reimport a batch given in CSV file.
     246
     247        CSV file must be of format as generated by createCSVLogFile
     248        method.
     249        """
     250        path = os.path.join(self._getStoragePath(), filename)
     251        reader = csv.DictReader(open(path, 'rb'), quoting=csv.QUOTE_ALL)
     252        entry = reader.next()
     253        cost = float(entry['cost'])
     254        num = int(entry['ac'])
     255        batch_name = '%s-%s' % (entry['serial'], num)
     256        if batch_name in self.keys():
     257            raise KeyError('Batch already exists: %s' % batch_name)
     258        batch = AccessCodeBatch(
     259            datetime.now(), creator, entry['serial'], cost, 0, num=num)
     260        num_entries = 0
     261        for row in reader:
     262            pin = row['ac']
     263            serial = int(row['serial'])
     264            rand_num = pin.rsplit('-', 1)[-1]
     265            batch.addAccessCode(serial, rand_num)
     266            num_entries += 1
     267        batch.entry_num = num_entries
     268        self[batch_name] = batch
     269        batch.createCSVLogFile()
     270        return
     271   
    226272class AccessCodePlugin(grok.GlobalUtility):
    227273    grok.name('accesscodes')
  • main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/accesscodes.txt

    r5128 r5132  
    330330      the same prefix, the new one will get the lowest unused number.
    331331
     332   .. method:: getImportFiles()
     333
     334      Get a list of basenames of available import files, suitable for
     335      feeding :meth:`reimport`.
     336
     337   .. method:: reimport(filename, creator=u'UNKNOWN')
     338
     339      Reimport a CSV log file of previously created AC batch.
     340
     341      ``filename`` is the name (basename) of the file residing in the
     342      accesscode storage's ``import`` directory.``creator`` is the
     343      user ID of the current user.
     344
    332345
    333346Access code plugin
  • main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/browser.py

    r5130 r5132  
    7272
    7373class ReimportBatchPage(WAeUPPage):
     74    """Screen for reimporting AC batches.
     75    """
    7476    grok.name('reimport')
    7577    grok.context(IAccessCodeBatchContainer)
     
    8082    pnav = 0
    8183
     84    def update(self, filenames=None, reimport=None, cancel=None):
     85        if cancel is not None:
     86            self.flash('Reimport cancelled.')
     87            self.redirect(self.url(self.context))
     88            return
     89        if reimport is None:
     90            return
     91        if not filenames:
     92            self.flash('No file chosen. Action cancelled.')
     93            self.redirect(self.url(self.context))
     94            return
     95        if isinstance(filenames, basestring):
     96            filenames = [filenames]
     97        userid = self.request.principal.id
     98        for filename in filenames:
     99            try:
     100                self.context.reimport(filename, userid)
     101            except KeyError:
     102                self.flash('This batch already exists: %s' % filename)
     103                continue
     104            self.flash('Successfully reimported: %s' % filename)
     105        self.redirect(self.url(self.context))
    82106       
     107   
    83108class BatchContainerBreadcrumb(Breadcrumb):
    84109    """A breadcrumb for ac batch containers.
  • main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/browser.txt

    r5128 r5132  
    183183    ...Archived BLA-1 (BLA-1_archive-...-zope.mgr.csv)...
    184184    ...Deleted batch BLA-1...
     185    ...
     186
     187
     188Reimporting Batches
     189===================
     190
     191We can reimport batches using the log files written when a batch was
     192created before. So one can reimport the freshly deleted BLA-1
     193batch.
     194
     195To do so we must copy the logfile into the ``imports`` dir of
     196accesscodes inside the university's datacenter storage. Otherwisae the
     197list of importable files is empty:
     198
     199    >>> browser.getLink('Reimport Scratch Card Batch').click()
     200    >>> print browser.contents
     201    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     202    ...
     203    ...No import batches available...
     204    ...
     205
     206We can cancel that operation:
     207
     208    >>> browser.getControl('Cancel').click()
     209
     210We copy the ``BLA-1`` batch logfile over to the ``imports`` directory:
     211
     212    >>> ac_storage = os.path.join(uploadpath, 'accesscodes')
     213    >>> logfile2 = os.path.join(ac_storage,
     214    ...                         sorted(os.listdir(ac_storage))[-3])
     215    >>> filename = os.path.basename(logfile2)
     216    >>> filename
     217    'BLA-1-...-zope.mgr.csv'
     218
     219    >>> import shutil
     220    >>> import_path = os.path.join(ac_storage, 'imports')
     221    >>> shutil.copy(logfile2, import_path)
     222
     223Now the file will be presented as import source:
     224
     225    >>> browser.getLink('Reimport Scratch Card Batch').click()
     226    >>> filename in browser.contents
     227    True
     228
     229If we do not tick a filename to import and click 'Reimport', we will
     230be warned:
     231
     232    >>> browser.getControl('Reimport').click()
     233    >>> print browser.contents
     234    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     235    ...No file chosen. Action cancelled...
     236
     237Now let's really reimport the batch:
     238
     239    >>> browser.getLink('Reimport Scratch Card Batch').click()
     240    >>> ctrl = browser.getControl(name='filenames')
     241    >>> ctrl.getControl(value=filename).selected = True
     242    >>> browser.getControl('Reimport').click()
     243
     244The batch does exist now again:
     245
     246    >>> print browser.contents
     247    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     248    ...Successfully reimported: BLA-1-...-zope.mgr.csv...
     249    ...
     250
     251If we try to reimport an existing batch, that won't work:
     252
     253    >>> browser.getLink('Reimport Scratch Card Batch').click()
     254    >>> ctrl = browser.getControl(name='filenames')
     255    >>> ctrl.getControl(value=filename).selected = True
     256    >>> browser.getControl('Reimport').click()
     257    >>> print browser.contents
     258    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     259    ...This batch already exists: BLA-1-...-zope.mgr.csv...
    185260    ...
    186261
     
    219294
    220295
     296
    221297Archive files
    222298-------------
     
    227303
    228304    >>> sorted(os.listdir(ac_storage))
    229     [..., 'BLA-1_archive-...-zope.mgr.csv']
     305    [..., 'BLA-1_archive-...-zope.mgr.csv', 'imports']
    230306
    231307Archive files eventually also contain infos about invalidation dates
    232308and have a slightly different format therefore.
    233309
    234     >>> archive_file = os.path.join(ac_storage, os.listdir(ac_storage)[-1])
     310    >>> archive_file = os.path.join(ac_storage,
     311    ...                             sorted(os.listdir(ac_storage))[-2])
    235312    >>> print open(archive_file, 'rb').read()
    236313    "prefix","serial","ac","student","date"
  • main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/browser_templates/reimportbatchpage.pt

    r5131 r5132  
    1 Hello
     1<h3>Reimport Access-Code Batches</h3>
     2<p>
     3  Please select the files to reimport. Please note, that batches with
     4  same name have to be deleted before.
     5</p>
     6<form method="POST">
     7  <table>
     8    <thead>
     9      <tr>
     10        <th>&nbsp;</th>
     11        <th>File</th>
     12      </tr>
     13    </thead>
     14    <tbody>
     15      <tr tal:repeat="filename context/getImportFiles"
     16          tal:attributes="class python: repeat['filename'].odd() and 'even' or 'odd'">
     17        <td>
     18          <input type="checkbox" name="filenames" value="filename"
     19                 tal:attributes="value filename" />
     20        </td>
     21        <td tal:content="filename">file.name</td>
     22      </tr>
     23      <tr tal:condition="python: len(list(context.getImportFiles())) == 0">
     24        <td colspan="5"><b>No import batches available</b></td>
     25      </tr>
     26    </tbody>
     27  </table>
     28
     29  <input type="submit" name="cancel" value="Cancel" />
     30  <input type="submit" name="reimport" value="Reimport" />
     31</form>
Note: See TracChangeset for help on using the changeset viewer.