source: main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/accesscodes.py @ 5114

Last change on this file since 5114 was 5112, checked in by uli, 15 years ago
  • Log creation of AC batches and their CSV files.
  • Optimize computation of random numbers.
File size: 4.8 KB
RevLine 
[5068]1"""Components to handle access codes.
2"""
[5110]3import csv
[5068]4import grok
[5110]5import os
[5068]6from random import SystemRandom as random
[5073]7from waeup.sirp.interfaces import IWAeUPSIRPPluggable
[5079]8from waeup.sirp.accesscodes.interfaces import (
9    IAccessCode, IAccessCodeBatch, IAccessCodeBatchContainer
10    )
[5068]11
[5102]12class ManageACBatches(grok.Permission):
13    grok.name('waeup.manageACBatches')
14
[5068]15class AccessCode(grok.Model):
16    grok.implements(IAccessCode)
17
[5079]18    def __init__(self, batch_serial, random_num, cost,
19                 invalidation_date=None, student_id=None):
[5068]20        self.batch_serial = batch_serial
21        self.random_num = random_num
22        self.cost = cost
23        self.invalidation_date = invalidation_date
24        self.student_id = student_id
25
26    @property
27    def representation(self):
28        return '%s-%s-%s' % (
29            self.batch_prefix, self.batch_num, self.random_num)
30
[5079]31    @property
32    def batch(self):
33        return getattr(self, '__parent__', None)
[5086]34
[5079]35    @property
36    def batch_prefix(self):
37        if self.batch is None:
38            return ''
39        return self.batch.prefix
[5086]40
[5079]41    @property
42    def batch_num(self):
43        if self.batch is None:
44            return ''
45        return self.batch.num
[5068]46
[5079]47class AccessCodeBatch(grok.Container):
[5068]48    """A batch of access codes.
49    """
50    grok.implements(IAccessCodeBatch)
51
[5086]52    def __init__(self, creation_date, creator, batch_prefix, cost,
53                 entry_num, num=None):
[5079]54        super(AccessCodeBatch, self).__init__()
[5068]55        self.creation_date = creation_date
56        self.creator = creator
[5079]57        self.prefix = batch_prefix
[5068]58        self.cost = cost
59        self.entry_num = entry_num
[5086]60        self.num = num
[5079]61
[5086]62    def createEntries(self):
[5079]63        """Create the entries for this batch.
64        """
[5112]65        rands = self.getNewRandomNum(num=self.entry_num)
[5079]66        for num in range(self.entry_num):
[5112]67            ac = AccessCode(num, rands[num], self.cost)
[5079]68            self[str(num)] = ac
[5112]69        return
70       
71    def getNewRandomNum(self, num=1):
72        """Create a set of ``num`` random numbers of 10 digits each.
[5086]73
[5068]74        The number is returned as string.
75        """
[5112]76        results = {}
77        while len(results) < num:
78            pin = ''
[5068]79            for x in range(10):
[5112]80                pin += str(random().randint(0, 9))
81            results[pin] = True
82        return results.keys()
[5073]83
[5110]84    def createCSVLogFile(self):
85        """Create a CSV file with data in batch.
86
87        Data will not contain invalidation date nor student ids.  File
88        will be created in ``accesscodes`` subdir of data center
89        storage path.
90
91        Returns name of created file.
92        """
93        site = grok.getSite()
94        storagepath = site['datacenter'].storage
95        ac_storage = os.path.join(storagepath, 'accesscodes')
96        if not os.path.exists(ac_storage):
97            os.mkdir(ac_storage)
98        date = self.creation_date.strftime('%Y_%m_%d_%H_%M_%S')
99        csv_path = os.path.join(
100            ac_storage, '%s-%s-%s-%s.csv' % (
101                self.prefix, self.num, date, self.creator)
102            )
103        writer = csv.writer(open(csv_path, 'w'), quoting=csv.QUOTE_ALL)
104        writer.writerow(['serial', 'ac', 'cost'])
105        writer.writerow([self.prefix, str(self.num), "%0.2f" % self.cost])
106        for key, value in self.items():
107            writer.writerow(
108                [str(value.batch_serial), str(value.representation)]
109                )
[5112]110        logger = site.logger
111        logger.info(
112            "Created batch %s-%s" % (self.prefix, self.num))
113        logger.info(
114            "Written batch CSV to %s" % csv_path)
[5110]115        return os.path.basename(csv_path)
116
117   
[5079]118class AccessCodeBatchContainer(grok.Container):
119    grok.implements(IAccessCodeBatchContainer)
[5073]120
[5079]121    def addBatch(self, batch):
[5086]122        """Add a batch.
123        """
124        batch.num = self.getNum(batch.prefix)
125        key = "%s-%s" % (batch.prefix, batch.num)
[5079]126        self[key] = batch
[5086]127        batch.createEntries()
128        self._p_changed = True
[5079]129
[5086]130    def getNum(self, prefix):
131        """Get next unused num for given prefix.
132        """
133        num = 1
134        prefix = prefix.upper()
135        while self.get('%s-%s' % (prefix, num), None):
136            num += 1
137        return num
[5095]138
[5073]139class AccessCodePlugin(grok.GlobalUtility):
140    grok.name('accesscodes')
141    grok.implements(IWAeUPSIRPPluggable)
142
143    def setup(self, site, name, logger):
[5079]144        site['accesscodes'] = AccessCodeBatchContainer()
145        logger.info('Installed container for access code batches.')
146        return
[5073]147
148    def update(self, site, name, logger):
[5107]149        if not 'accesscodes' in site.keys():
150            logger.info('Updating site at %s. Installing access codes.' % (
151                    site,))
152            self.setup(site, name, logger)
153        else:
154            logger.info(
155                'AccessCodePlugin: Updating site at %s: Nothing to do.' % (
156                    site, ))
157        return
Note: See TracBrowser for help on using the repository browser.