"""Components to handle access codes. """ import csv import grok import os from random import SystemRandom as random from waeup.sirp.interfaces import IWAeUPSIRPPluggable from waeup.sirp.accesscodes.interfaces import ( IAccessCode, IAccessCodeBatch, IAccessCodeBatchContainer ) class ManageACBatches(grok.Permission): grok.name('waeup.manageACBatches') class AccessCode(grok.Model): grok.implements(IAccessCode) def __init__(self, batch_serial, random_num, cost, invalidation_date=None, student_id=None): self.batch_serial = batch_serial self.random_num = random_num self.cost = cost self.invalidation_date = invalidation_date self.student_id = student_id @property def representation(self): return '%s-%s-%s' % ( self.batch_prefix, self.batch_num, self.random_num) @property def batch(self): return getattr(self, '__parent__', None) @property def batch_prefix(self): if self.batch is None: return '' return self.batch.prefix @property def batch_num(self): if self.batch is None: return '' return self.batch.num class AccessCodeBatch(grok.Container): """A batch of access codes. """ grok.implements(IAccessCodeBatch) def __init__(self, creation_date, creator, batch_prefix, cost, entry_num, num=None): super(AccessCodeBatch, self).__init__() self.creation_date = creation_date self.creator = creator self.prefix = batch_prefix self.cost = cost self.entry_num = entry_num self.num = num def createEntries(self): """Create the entries for this batch. """ rands = self.getNewRandomNum(num=self.entry_num) for num in range(self.entry_num): ac = AccessCode(num, rands[num], self.cost) self[str(num)] = ac return def getNewRandomNum(self, num=1): """Create a set of ``num`` random numbers of 10 digits each. The number is returned as string. """ results = {} while len(results) < num: pin = '' for x in range(10): pin += str(random().randint(0, 9)) results[pin] = True return results.keys() def createCSVLogFile(self): """Create a CSV file with data in batch. Data will not contain invalidation date nor student ids. File will be created in ``accesscodes`` subdir of data center storage path. Returns name of created file. """ site = grok.getSite() storagepath = site['datacenter'].storage ac_storage = os.path.join(storagepath, 'accesscodes') if not os.path.exists(ac_storage): os.mkdir(ac_storage) date = self.creation_date.strftime('%Y_%m_%d_%H_%M_%S') csv_path = os.path.join( ac_storage, '%s-%s-%s-%s.csv' % ( self.prefix, self.num, date, self.creator) ) writer = csv.writer(open(csv_path, 'w'), quoting=csv.QUOTE_ALL) writer.writerow(['serial', 'ac', 'cost']) writer.writerow([self.prefix, str(self.num), "%0.2f" % self.cost]) for key, value in self.items(): writer.writerow( [str(value.batch_serial), str(value.representation)] ) logger = site.logger logger.info( "Created batch %s-%s" % (self.prefix, self.num)) logger.info( "Written batch CSV to %s" % csv_path) return os.path.basename(csv_path) class AccessCodeBatchContainer(grok.Container): grok.implements(IAccessCodeBatchContainer) def addBatch(self, batch): """Add a batch. """ batch.num = self.getNum(batch.prefix) key = "%s-%s" % (batch.prefix, batch.num) self[key] = batch batch.createEntries() self._p_changed = True def getNum(self, prefix): """Get next unused num for given prefix. """ num = 1 prefix = prefix.upper() while self.get('%s-%s' % (prefix, num), None): num += 1 return num class AccessCodePlugin(grok.GlobalUtility): grok.name('accesscodes') grok.implements(IWAeUPSIRPPluggable) def setup(self, site, name, logger): site['accesscodes'] = AccessCodeBatchContainer() logger.info('Installed container for access code batches.') return def update(self, site, name, logger): if not 'accesscodes' in site.keys(): logger.info('Updating site at %s. Installing access codes.' % ( site,)) self.setup(site, name, logger) else: logger.info( 'AccessCodePlugin: Updating site at %s: Nothing to do.' % ( site, )) return