def validate(self): config_schema = schema.Schema({ 'name': str, 'app_sequence': list, 'participation_fee': object, 'real_world_currency_per_point': object, 'num_demo_participants': int, 'doc': str, object: object, }) try: config_schema.validate(self) except schema.SchemaError as e: raise ValueError('settings.SESSION_CONFIGS: {}'.format(e)) validate_identifier( self['name'], identifier_description='settings.SESSION_CONFIG name' ) app_sequence = self['app_sequence'] if len(app_sequence) != len(set(app_sequence)): msg = ( 'settings.SESSION_CONFIGS: ' 'app_sequence of "{}" ' 'must not contain duplicate elements. ' 'If you want multiple rounds, ' 'you should set Constants.num_rounds.') raise ValueError(msg.format(self['name'])) if len(app_sequence) == 0: raise ValueError( 'settings.SESSION_CONFIGS: Need at least one subsession.') self.setdefault('display_name', self['name']) self.setdefault('doc', '') # TODO: fixed_pay is deprecated as of 2015-05-07, # in favor of participation_fee. make this required at some point. if (('participation_fee' not in self) and ('fixed_pay' in self)): warn_msg = ( "'fixed_pay' is deprecated; " "you should rename it to 'participation_fee'.") warnings.warn(warn_msg, OtreeDeprecationWarning) self['participation_fee'] = self['fixed_pay'] self['participation_fee'] = RealWorldCurrency( self['participation_fee']) # normalize to decimal so we can do multiplications, etc # quantize because the original value may be a float, # which when converted to Decimal may have some 'decimal junk' # like 0.010000000000000000208166817... self['real_world_currency_per_point'] = Decimal( self['real_world_currency_per_point'] ).quantize(Decimal('0.00001'))
def load_participant_labels_to_db(self): if self.has_participant_labels(): encodings = ['ascii', 'utf-8', 'utf-16'] for e in encodings: try: plabel_path = self.participant_label_file with codecs.open(plabel_path, "r", encoding=e) as f: seen = set() labels = [] for line in f: label = line.strip() if not label: continue label = validate_identifier( line.strip(), identifier_description='participant label' ) if label not in seen: labels.append(label) seen.add(label) except UnicodeDecodeError: continue except OSError as err: # this code is equivalent to "except FileNotFoundError:" # but works in py2 and py3 if err.errno == errno.ENOENT: msg = ( 'settings.ROOMS: The room "{}" references ' ' nonexistent participant_label_file "{}".' ) raise IOError( msg.format(self.name, self.participant_label_file)) raise err else: with global_lock(): # before I used select_for_update to prevent race # conditions. But the queryset was not evaluated # so it did not hit the DB. maybe simpler to use an # explicit lock ExpectedRoomParticipant.objects.select_for_update() ExpectedRoomParticipant.objects.filter( room_name=self.name).delete() ExpectedRoomParticipant.objects.bulk_create( ExpectedRoomParticipant( room_name=self.name, participant_label=participant_label ) for participant_label in labels ) self._participant_labels_loaded = True return raise Exception( 'settings.ROOMS: participant_label_file "{}" ' 'not encoded correctly.'.format(self.participant_label_file) ) raise Exception('no guestlist')
def __init__(self, config_dict): self.participant_label_file = config_dict.get('participant_label_file') self.name = validate_identifier( config_dict['name'], identifier_description='settings.ROOMS room name') self.display_name = config_dict['display_name'] # secure URLs are complicated, don't use them by default self.use_secure_urls = config_dict['use_secure_urls'] self.pin_code = config_dict.get('pin_code') self._participant_labels_loaded = False if self.use_secure_urls and not self.participant_label_file: raise ValueError( 'Room "{}": you must either set "participant_label_file", ' 'or set "use_secure_urls": False'.format(self.name) )