def test_get_property(self): cal = self.cal1 # Component property events = cal.get_components('VEVENT') properties = events[0][-1] expected = u'Résumé' property = events[0].get_property('SUMMARY') self.assertEqual(property.value, expected) expected = 1 property = events[0].get_property('PRIORITY') self.assertEqual(property.value, expected) # Component properties properties = {} properties['MYADD'] = Property(u'Résumé à crêtes') value = Property(u'Property added by calling add_property') properties['DESCRIPTION'] = value member = '"mailto:[email protected]"' value = Property('mailto:[email protected]', MEMBER=[member]) properties['ATTENDEE'] = value properties['type'] = 'VEVENT' uid = cal.add_record(properties).UID event = cal.get_component_by_uid(uid)[0] properties = event.get_property() self.assertEqual('MYADD' in properties, True) self.assertEqual('DESCRIPTION' in properties, True) self.assertEqual('ATTENDEE' in properties, True) self.assertEqual('VERSION' in properties, False)
def test_add_property(self): """Test adding a property to any component. """ cal = self.cal2 event = cal.get_components('VEVENT')[1] # other property (MYADD) name, value = 'MYADD', Property(u'Résumé à crêtes') cal.update_record(event.id, **{name: value}) property = event.get_property(name) self.assertEqual(property[0], value) self.assertEqual(property[0].value, value.value) # property DESCRIPTION name = 'DESCRIPTION' value = Property(u'Property added by calling add_property') cal.update_record(event.id, **{name: value}) property = event.get_property(name) self.assertEqual(property, value) # property ATTENDEE name = 'ATTENDEE' value = event.get_property(name) member = '"mailto:[email protected]"' value.append(Property('mailto:[email protected]', MEMBER=[member])) cal.update_record(event.id, **{name: value}) property = event.get_property(name) self.assertEqual(str(property[0].value), 'mailto:[email protected]') self.assertEqual(property[1].parameters, {'MEMBER': [member]}) self.assertEqual(property[1], value[1])
def get_property(self, name, language=None): if name not in self.properties: return None value, lang = self.get_property_and_language(name, language=language) if lang: return Property(value, lang=lang) return Property(value)
def get_property(self, name, language=None): property = self.metadata.get_property(name, language=language) if property: return property field = self.get_field(name) if field is None: return None default = field.get_default() if field.multiple: return [Property(x) for x in default] return Property(default)
def reset_register_key(self, username): cc_list = self.get_property('cc_list') # Filter out username cc_list = [cc for cc in cc_list if cc.value != username] # Create new dict to force metadata commit cc_list.append(Property(username)) self.set_property('cc_list', cc_list)
def setUp(self): metadata = Metadata(cls=WebPage) title = Property(u'Hello World', lang='en') metadata.set_property('title', title) self.metadata = metadata # Sandbox vfs.make_folder('sandbox')
def _set_value(self, resource, name, value, language=None, **kw): if language: kw['lang'] = language if kw: value = Property(value, **kw) resource.metadata.set_property(name, value)
def to_ical(self, context): """Serialize as an ical file, generally named .ics """ lines = ['BEGIN:VCALENDAR\n', 'VERSION:2.0\n', 'PRODID:-//itaapy.com/NONSGML ikaaro icalendar V1.0//EN\n'] # Calendar components for event in self.search_resources(cls=Event): lines.append('BEGIN:VEVENT\n') for ikaaro_name, ics_name in ikaaro_to_ics: property = event.get_property(ikaaro_name) lang = property.get_parameter('lang') if lang: property = Property(property.value, LANGUAGE=lang) p_schema = {'LANGUAGE': String(multiple=False)} else: p_schema = None datatype = event.get_field(ikaaro_name).datatype line = property_to_str(ics_name, property, datatype, p_schema) lines.append(line) lines.append('END:VEVENT\n') lines.append('END:VCALENDAR\n') return ''.join(lines)
def test_component_set_property(self): """Test setting a new value to an existant component property. """ cal = self.cal1 event = cal.get_components('VEVENT')[0] name, value = 'SUMMARY', Property('This is a new summary') cal.update_component(event.uid, **{name: value}) self.assertEqual(event.get_property_values(name), value) member = '"mailto:[email protected]"' value = [ Property('mailto:[email protected]', MEMBER=[member]), Property('mailto:[email protected]'), Property('mailto:[email protected]')] cal.update_component(event.uid, ATTENDEE=value) self.assertEqual(event.get_property_values('ATTENDEE'), value)
def to_ical(self): """Serialize as an ical file, generally named .ics """ lines = [] line = 'BEGIN:VCALENDAR\n' lines.append(Unicode.encode(line)) # Calendar properties properties = (('VERSION', u'2.0'), ('PRODID', u'-//itaapy.com/NONSGML ikaaro icalendar V1.0//EN')) for name, value in properties: value = Property(value) line = self.encode_property(name, value) lines.append(line[0]) # Calendar components for record in self.records: if record is not None: seq = 0 c_type = record.type # Ignore some components (like DAYLIGHT, STANDARD, ...) # keeping only VEVENT, VTIMEZONE, V.., and x-name ones if not c_type.startswith('V') and not c_type.startswith('X'): continue for version in record: line = 'BEGIN:%s\n' % c_type lines.append(Unicode.encode(line)) line = '' # Properties names = version.keys() names.sort() for name in names: if name in ('id', 'ts', 'type'): continue elif name == 'DTSTAMP': value = version['ts'] else: value = version[name] if name == 'SEQUENCE': value.value += seq # Insert inner components elif name == 'inner': line = self.encode_inner_components(name, value) else: name = name.upper() line = self.encode_property(name, value) lines.extend(line) line = 'END:%s\n' % c_type lines.append(Unicode.encode(line)) seq += 1 line = 'END:VCALENDAR\n' lines.append(Unicode.encode(line)) return ''.join(lines)
def new(self): properties = (('VERSION', u'2.0'), ('PRODID', u'-//itaapy.com/NONSGML ikaaro icalendar V1.0//EN')) for name, value in properties: self.properties[name] = Property(value) # The encoding self.encoding = 'UTF-8'
def test_add_to_calendar(self): """Test to add property and component to an empty icalendar object. """ cal = iCalendar() cal.add_component('VEVENT') self.assertEqual(len(cal.get_components('VEVENT')), 1) value = Property('PUBLISH') cal.set_property('METHOD', value) self.assertEqual(cal.get_property_values('METHOD'), value)
def test_property(self): """Test to create, access and encode a property with or without parameters. """ # Property without parameter expected = ['SUMMARY:This is the summary\n'] property_value = Property('This is the summary') output = self.cal1.encode_property('SUMMARY', property_value) self.assertEqual(output, expected) # Property with one parameter expected = ['ATTENDEE;MEMBER="mailto:[email protected]":' 'mailto:[email protected]\n'] member = 'mailto:[email protected]' value = Property('mailto:[email protected]', MEMBER=[member]) output = self.cal1.encode_property('ATTENDEE', value) self.assertEqual(output, expected)
def test_icalendar_set_property(self): """Test setting a new value to an existant icalendar property. """ cal = self.cal1 name, value = 'VERSION', Property('2.1') cal.set_property(name, value) self.assertEqual(cal.get_property_values(name), value) cal.set_property(name, [value, ]) self.assertEqual(cal.get_property_values(name), value)
def _make_resource(cls, folder, name, *args, **kw): OrderedTable._make_resource(cls, folder, name) table = BaseCountriesZones() zones = [] csv = ro_database.get_handler(get_abspath('data/countries.csv'), CSVFile) for line in csv.get_rows(): zone = unicode(line[1], 'utf-8') if zone not in zones: zones.append(zone) table.add_record({'title': Property(zone, language='fr')}) folder.set_handler(name, table)
def test_add_property(self): """Test adding a property to any component. """ cal = self.cal2 event = cal.get_components('VEVENT')[1] # other property (MYADD) name, value = 'MYADD', Property(u'Résumé à crêtes') cal.update_component(event.uid, **{name: value}) property = event.get_property_values(name) self.assertEqual(property[0], value) self.assertEqual(property[0].value, value.value) # property DESCRIPTION name = 'DESCRIPTION' value = Property(u'Property added by calling add_property') cal.update_component(event.uid, **{name: value}) property = event.get_property_values(name) self.assertEqual(property, value) # property ATTENDEE name = 'ATTENDEE' value = event.get_property_values(name) member = '"mailto:[email protected]"' value.append(Property('mailto:[email protected]', MEMBER=[member])) cal.update_component(event.uid, **{name: value}) property = event.get_property_values(name) self.assertEqual(str(property[0].value), 'mailto:[email protected]') self.assertEqual(property[1].parameters, {'MEMBER': [member]}) self.assertEqual(property[1], value[1])
def _set_property(self, name, value): properties = self.properties # Case 1: Remove property if value is None: if name in properties: del properties[name] return # Case 2: Multiple (replace) p_type = type(value) if p_type is list: properties[name] = [ x if type(x) is Property else Property(x) for x in value ] return # Case 3: Multilingual if p_type is Property: if value.parameters and 'lang' in value.parameters: language = value.parameters['lang'] properties.setdefault(name, {})[language] = value return else: value = Property(value) # Case 4: Simple cls = self.database.get_resource_class(self.format) field = cls.get_field(name) if field is None or field.multiple is False: properties[name] = value return # Case 5: Multiple (append) if not field.datatype.is_empty(value.value): properties.setdefault(name, []).append(value)
def add_record(self, kw): if 'UID' not in kw: type = kw.get('type', 'UNKNOWN') kw['UID'] = self.generate_uid(type) id = len(self.records) record = Record(id, self.record_properties) version = self.properties_to_dict(kw) version['ts'] = Property(datetime.now()) record.append(version) # Change self.set_changed() self.added_records.append((id, 0)) self.records.append(record) self.catalog.index_document(record) # Back return record
def add_version(self, properties): # Sequence in properties only if just loading file if 'SEQUENCE' in properties: sequence = properties.pop('SEQUENCE') sequence = sequence.value else: sequences = self.get_sequences() if sequences: sequence = sequences[-1] + 1 else: sequence = 0 # Timestamp if 'DTSTAMP' not in properties: properties['DTSTAMP'] = Property(datetime.today()) self.versions[sequence] = properties
def set_register_key(self, username, unregister=False): cc_list = self.get_property('cc_list') status = 'U' if unregister is True else 'S' # Find existing key for cc in cc_list: key = cc.get_parameter('key') if (cc.value == username and cc.get_parameter('status') == status and key is not None): # Reuse found key return key # Generate key key = generate_password(30) # Filter out username cc_list = [cc for cc in cc_list if cc.value != username] # Create new dict to force metadata commit cc_list.append(Property(username, status=status, key=key)) self.set_property('cc_list', cc_list) return key
def _make_resource(cls, folder, name, *args, **kw): Table._make_resource(cls, folder, name) # Import CSV with list of countries zones = [] table = BaseCountries() csv = ro_database.get_handler(get_abspath('data/countries.csv'), CSVFile) for line in csv.get_rows(): country = unicode(line[0], 'utf-8') zone = unicode(line[1], 'utf-8') if zone not in zones: zones.append(zone) table.add_record({ 'title': Property(country, language='fr'), 'zone': str(zones.index(zone)), 'enabled': True }) folder.set_handler(name, table)
def action_upload(self, resource, context, form): filename, mimetype, body = form['file'] name, type, language = FileName.decode(filename) # Check the filename is good title = form['title'].strip() name = checkid(title) or checkid(name) if name is None: context.message = messages.MSG_BAD_NAME return # Get the container container = context.root.get_resource(form['target_path']) # Check the name is free if container.get_resource(name, soft=True) is not None: context.message = messages.MSG_NAME_CLASH return # Check it is of the expected type cls = context.database.get_resource_class(mimetype) if not self.can_upload(cls): error = u'The given file is not of the expected type.' context.message = ERROR(error) return kw = {'data': body, 'filename': filename} # Add the image to the resource child = container.make_resource(name, cls, **kw) # The title language = resource.get_edit_languages(context)[0] title = Property(title, lang=language) child.metadata.set_property('title', title) # Get the path path = child.abspath action = self.get_resource_action(context) if action: path = '%s%s' % (path, action) # Return javascript scripts = self.get_scripts(context) context.add_script(*scripts) return self.get_javascript_return(context, path)
def search_events(self, subset=None, **kw): """Return a list of Record objects of type 'VEVENT' corresponding to the given filters. It should be used like this, for example: events = cal.search_events( STATUS='TENTATIVE', PRIORITY=1, ATTENDEE=['mailto:[email protected]', 'mailto:[email protected]']) ** With a list of values, events match if at least one value matches It searches into all components or in the provided subset list of components. """ res_events = [] # Get the list of differents property names used to filter filters = kw.keys() # For each event events = subset or self.search(type='VEVENT') for event in events: if event in res_events: continue version = self.get_record(id=event.id)[-1] # For each filter for filter in filters: # If filter not in component, go to next one if filter not in version: break # Test filter expected = kw.get(filter) value = version[filter] datatype = self.get_record_datatype(filter) if getattr(datatype, 'multiple', False) is True: value = [ isinstance(x, Property) and x or Property(x) for x in value ] if not isinstance(expected, list): expected = [ expected, ] for item in value: if item.value in expected: break elif item.value == expected: break else: break else: if not isinstance(value, Property): value = Property(value) if value.value != expected: break else: res_events.append(event) return res_events
def _load_state_from_file(self, file): # Read the data and figure out the encoding data = file.read() encoding = guess_encoding(data) self.encoding = encoding # Parse lines = [] for name, value, parameters in parse_table(data): # Deserialize datatype = self.get_record_datatype(name) if isinstance(datatype, Unicode): value = datatype.decode(value, encoding=encoding) else: value = datatype.decode(value) # Build the value (a Property instance) deserialize_parameters(parameters, self.record_parameters) value = Property(value, **parameters) # Append lines.append((name, value)) # Read first line first = lines[0] if (first[0] != 'BEGIN' or first[1].value != 'VCALENDAR' or len(first[1].parameters) != 0): raise ValueError, 'icalendar must begin with BEGIN:VCALENDAR' lines = lines[1:] ################################################################### # Read properties n_line = 0 for name, value in lines: if name == 'BEGIN': break elif name == 'END': break elif name == 'VERSION': if 'VERSION' in self.properties: raise ValueError, 'VERSION can appear only one time' elif name == 'PRODID': if 'PRODID' in self.properties: raise ValueError, 'PRODID can appear only one time' # Add the property self.properties[name] = value n_line += 1 # The properties VERSION and PRODID are mandatory if ('VERSION' not in self.properties or 'PRODID' not in self.properties): raise ValueError, 'PRODID or VERSION parameter missing' lines = lines[n_line:] ################################################################### # Read components c_type = None c_inner_type = None uid = None for prop_name, prop_value in lines[:-1]: if prop_name in ('PRODID', 'VERSION'): raise ValueError, 'PRODID and VERSION must appear before '\ 'any component' if prop_name == 'BEGIN': if c_type is None: c_type = prop_value.value c_properties = {} c_inner_components = [] else: # Inner component like DAYLIGHT or STANDARD c_inner_type = prop_value.value c_inner_properties = {} continue if prop_name == 'END': value = prop_value.value if value == c_type: if uid is None: raise ValueError, 'UID is not present' if uid in self.components: component = self.components[uid] component.add_version(c_properties) else: component = Component(c_type, uid) component.add_version(c_properties) component.c_inner_components = c_inner_components self.components[uid] = component # Next c_type = None uid = None # Inner component elif value == c_inner_type: inner_component = InnerComponent(c_inner_type) inner_component.add_version(c_inner_properties) c_inner_components.append(inner_component) c_inner_type = None else: raise ValueError, 'Component %s found, %s expected' \ % (value, c_inner_type) else: datatype = self.get_record_datatype(prop_name) if c_inner_type is None: if prop_name in ('UID', 'TZID'): uid = prop_value.value else: if getattr(datatype, 'multiple', False) is True: value = c_properties.setdefault(prop_name, []) value.append(prop_value) else: # Check the property has not yet being found if prop_name in c_properties: msg = ('the property %s can be assigned only ' 'one value' % prop_name) raise ValueError, msg # Set the property c_properties[prop_name] = prop_value else: # Inner component properties if getattr(datatype, 'multiple', False) is True: value = c_inner_properties.setdefault(prop_name, []) value.append(prop_value) else: # Check the property has not yet being found if prop_name in c_inner_properties: msg = ('the property %s can be assigned only one' ' value' % prop_name) raise ValueError, msg value = prop_value # Set the property c_inner_properties[prop_name] = value ################################################################### # Index components for uid in self.components: component = self.components[uid] self.catalog.index_document(component)
def load_state_from_ical_file(self, file): """Load state from the given ical file. """ self.reset() self.set_changed() components = {} # Read the data data = file.read() # Parse lines = [] for name, value, parameters in parse_table(data): # Timestamp (ts), Schema, or Something else datatype = self.get_record_datatype(name) value = datatype.decode(value) property = Property(value, **parameters) # Append lines.append((name, property)) # Read first line first = lines[0] if (first[0] != 'BEGIN' or first[1].value != 'VCALENDAR' or len(first[1].parameters) != 0): raise ValueError, 'icalendar must begin with BEGIN:VCALENDAR' lines = lines[1:] ################################################################### # Skip properties # TODO Currently tables are not able to handler global properties, # we must implement this feature to be able to load from ical files. n_line = 0 for name, value in lines: if name == 'BEGIN': break elif name == 'END': break n_line += 1 lines = lines[n_line:] ################################################################### # Read components c_type = None c_inner_type = None uid = None records = self.records record_properties = self.record_properties id = 0 uids = {} for prop_name, prop_value in lines[:-1]: if prop_name in ('PRODID', 'VERSION'): raise ValueError, 'PRODID and VERSION must appear before '\ 'any component' if prop_name == 'BEGIN': if c_type is None: c_type = prop_value.value c_properties = {} c_inner_components = [] else: # Inner component like DAYLIGHT or STANDARD c_inner_type = prop_value.value c_inner_properties = {} continue if prop_name == 'END': value = prop_value.value if value == c_type: if uid is None: raise ValueError, 'UID is not present' record = self.get_record(id) or Record( id, record_properties) c_properties['type'] = Property(c_type) c_properties['UID'] = Property(uid) sequence = c_properties.get('SEQUENCE', None) c_properties['SEQUENCE'] = sequence or Property(0) c_properties['ts'] = Property(datetime.now()) # Add ids of inner components if c_inner_components: c_inner_components = [ Property(x) for x in c_inner_components ] c_properties['inner'] = c_inner_components record.append(c_properties) if uid in uids: n = uids[uid] + 1 uids[uid] = n else: n = 0 uids[uid] = 0 self.added_records.append((id, n)) records.append(record) # Next c_type = None uid = None if n == 0: id = id + 1 # Inner component elif value == c_inner_type: record = self.get_record(id) or Record( id, record_properties) c_inner_properties['type'] = Property(c_inner_type) sequence = c_inner_properties.get('SEQUENCE', None) c_inner_properties['SEQUENCE'] = sequence or Property(0) c_inner_properties['ts'] = Property(datetime.now()) record.append(c_inner_properties) c_inner_components.append(id) self.added_records.append((id, 0)) records.append(record) # Next c_inner_type = None id = id + 1 else: raise ValueError, 'Component %s found, %s expected' \ % (value, c_inner_type) else: datatype = self.get_record_datatype(prop_name) if c_inner_type is None: if prop_name in ('UID', 'TZID'): uid = prop_value.value else: if getattr(datatype, 'multiple', False) is True: value = c_properties.setdefault(prop_name, []) value.append(prop_value) else: # Check the property has not yet being found if prop_name in c_properties: raise ValueError, \ "property '%s' can occur only once" % name # Set the property c_properties[prop_name] = prop_value else: # Inner component properties if getattr(datatype, 'multiple', False) is True: value = c_inner_properties.setdefault(prop_name, []) value.append(prop_value) else: # Check the property has not yet being found if prop_name in c_inner_properties: msg = ('the property %s can be assigned only one' ' value' % prop_name) raise ValueError, msg # Set the property c_inner_properties[prop_name] = prop_value # Index the records for record in records: if record is not None: self.catalog.index_document(record)
def _load_state_from_file(self, file): properties = self.properties data = file.read() parser = parse_table(data) # Read the format & version name, value, parameters = parser.next() if name != 'format': raise ValueError, 'unexpected "%s" property' % name if 'version' in parameters: version = parameters.pop('version') if len(version) > 1: raise ValueError, 'version parameter cannot be repeated' self.version = version[0] if parameters: raise ValueError, 'unexpected parameters for the format property' self.format = value # Get the schema resource_class = self.database.get_resource_class(value) # Parse for name, value, parameters in parser: if name == 'format': raise ValueError, 'unexpected "format" property' # 1. Get the field field = resource_class.get_field(name) if field is None: msg = 'unexpected field "%s"' % name if resource_class.fields_soft: log_warning(msg, domain='itools.database') field = DefaultField else: raise ValueError, msg # 2. Deserialize the parameters params_schema = field.parameters_schema params_default = field.parameters_schema_default try: deserialize_parameters(parameters, params_schema, params_default) except ValueError, e: msg = 'in class "{0}" property "{1}": {2}' raise ValueError, msg.format(resource_class, name, e) # 3. Get the datatype properties if field.multiple and field.multilingual: error = 'property "%s" is both multilingual and multiple' raise ValueError, error % name # 4. Build the property datatype = field.datatype value = datatype.decode(value) property = Property(value, **parameters) # Case 1: Multilingual if field.multilingual: language = parameters.get('lang') if language is None: err = 'multilingual property "%s" is missing the language' raise ValueError, err % name properties.setdefault(name, {})[language] = property # Case 2: multiple elif field.multiple: properties.setdefault(name, []).append(property) # Case 3: simple else: properties[name] = property