def add(self, fd): """Add field description to the container.""" chooser = INameChooser(self.context) name = chooser.chooseName(fd.name, fd) self.context[name] = fd return fd
def ical_import(container, ics_resource, event_type, sync_strategy=base.SYNC_KEEP_NEWER): cal = icalendar.Calendar.from_ical(ics_resource) events = cal.walk('VEVENT') cat = getToolByName(container, 'portal_catalog') container_path = '/'.join(container.getPhysicalPath()) def _get_by_sync_uid(uid): return cat(sync_uid=uid, path={'query': container_path, 'depth': 1}) def _get_prop(prop, item, default=None): ret = default if prop in item: ret = safe_unicode(item.decoded(prop)) return ret def _from_list(ical, prop): """For EXDATE and RDATE recurrence component properties, the dates can be defined within one EXDATE/RDATE line or for each date an individual line. In the latter case, icalendar creates a list. This method handles this case. TODO: component property parameters like TZID are not used here. """ val = ical[prop] if prop in ical else [] if not isinstance(val, list): val = [val] # Zip multiple lines into one, since jquery.recurrenceinput.js does # not support multiple lines here # https://github.com/collective/jquery.recurrenceinput.js/issues/15 ret = '' for item in val: ret = '%s,' % ret if ret else ret # insert linebreak ret = '%s%s' % (ret, item.to_ical()) return '%s:%s' % (prop, ret) if ret else None count = 0 for item in events: start = _get_prop('DTSTART', item) end = _get_prop('DTEND', item) if not end: duration = _get_prop('DURATION', item) if duration: end = start + duration # else: whole day or open end whole_day = False open_end = False if is_date(start) and (is_date(end) or end is None): # All day / whole day events # End must be same type as start (RFC5545, 3.8.2.2) whole_day = True if end is None: end = start if start < end: # RFC5545 doesn't define clearly, if all day events should have # a end date one day after the start day at 0:00. # Internally, we handle all day events with start=0:00, # end=:23:59:59, so we substract one day here. end = end - datetime.timedelta(days=1) start = base.dt_start_of_day(date_to_datetime(start)) end = base.dt_end_of_day(date_to_datetime(end)) elif is_datetime(start) and end is None: # Open end event, see RFC 5545, 3.6.1 open_end = True end = base.dt_end_of_day(date_to_datetime(start)) assert (is_datetime(start)) assert (is_datetime(end)) # Set timezone, if not already set tz = base.default_timezone(container, as_tzinfo=True) if not getattr(start, 'tzinfo', False): start = tz.localize(start) if not getattr(end, 'tzinfo', False): end = tz.localize(end) title = _get_prop('SUMMARY', item) description = _get_prop('DESCRIPTION', item) location = _get_prop('LOCATION', item) url = _get_prop('URL', item) rrule = _get_prop('RRULE', item) rrule = 'RRULE:%s' % rrule.to_ical() if rrule else '' rdates = _from_list(item, 'RDATE') exdates = _from_list(item, 'EXDATE') rrule = '\n'.join([it for it in [rrule, rdates, exdates] if it]) # TODO: attendee-lists are not decoded properly and contain only # vCalAddress values attendees = item.get('ATTENDEE', ()) contact = _get_prop('CONTACT', item) categories = item.get('CATEGORIES', ()) if getattr(categories, '__iter__', False): categories = tuple([safe_unicode(it) for it in categories]) ext_modified = utc(_get_prop('LAST-MODIFIED', item)) content = None new_content_id = None existing_event = None sync_uid = _get_prop('UID', item) if sync_uid and sync_strategy is not base.SYNC_NONE: existing_event = _get_by_sync_uid(sync_uid) if existing_event: if sync_strategy == base.SYNC_KEEP_MINE: # On conflict, keep mine continue exist_event = existing_event[0].getObject() acc = IEventAccessor(exist_event) if sync_strategy == base.SYNC_KEEP_NEWER and\ (not ext_modified or acc.last_modified > ext_modified): # Update only if modified date was passed in and it is not # older than the current modified date. The client is not # expected to update the "last-modified" property, it is the # job of the server (calendar store) to keep it up to date. # This makes sure the client did the change on an up-to-date # version of the object. See # http://tools.ietf.org/search/rfc5545#section-3.8.7.3 continue # Else: update content = exist_event else: new_content_id = str(random.randint(0, 99999999)) container.invokeFactory(event_type, id=new_content_id, title=title, description=description) content = container[new_content_id] assert (content) # At this point, a content must be available. event = IEventAccessor(content) event.title = title event.description = description event.start = start event.end = end event.whole_day = whole_day event.open_end = open_end event.location = location event.event_url = url event.recurrence = rrule event.attendees = attendees event.contact_name = contact event.subjects = categories if sync_uid and sync_strategy is not base.SYNC_NONE: # Set the external sync_uid for sync strategies other than # SYNC_NONE. event.sync_uid = sync_uid notify(ObjectModifiedEvent(content)) # Use commits instead of savepoints to avoid "FileStorageError: # description too long" on large imports. transaction.get().commit() # Commit before rename if new_content_id and new_content_id in container: # Rename with new id from title, if processForm didn't do it. chooser = INameChooser(container) new_id = chooser.chooseName(title, content) content.aq_parent.manage_renameObject(new_content_id, new_id) # Do this at the end, otherwise it's overwritten if ext_modified: event.last_modified = ext_modified count += 1 return {'count': count}
def add(self, term): """Add `term` to the container.""" chooser = INameChooser(self.context) name = chooser.chooseName("", term) self.context[name] = term return term
def upload(self, files, title='', description=''): if not self.doc.isDocument(): return #import pdb;pdb.set_trace() overwrite = True current_files = self.doc.getItem(self.fieldName, {}) if not current_files: current_files = dict() #Utile ma pericoloso: se cambio da multi a single elimino tutti i file.. da vedere # if not self.multi: # for fileId in current_files.keys(): # self.doc.deletefile(fileId) if not isinstance(files, list): files = [files] namechooser = INameChooser(self.doc) info = { 'name': 'File-Name.jpg', 'title': '', 'description': '', 'size': 999999, 'url': '@@getattachment?', 'thumbnail_url': '//nohost.org', 'delete_url': '//nohost.org', 'delete_type': 'DELETE', 'field_name': self.fieldName } results = [] for item in files: if item.filename: # if overwrite and filename in self.objectIds(): # self.doc.deletefile(filename) contenttype = item.headers.get('Content-Type') filename = safe_unicode(item.filename) data = item.read() id_name = '' title = title and title[0] or filename #non usata description = description and description[0] or '' # Get a unique id here id_name = namechooser.chooseName(title, self.doc) info["name"] = id_name info["title"] = title info["description"] = description info["thumbnail_url"] = self.getIcon(contenttype) info["content_type"] = contenttype try: blob = BlobWrapper(contenttype) except: # XXX Except what? # BEFORE PLONE 4.0.1 blob = BlobWrapper() file_obj = blob.getBlob().open('w') file_obj.write(data) file_obj.close() blob.setFilename(id_name) blob.setContentType(contenttype) info['size'] = blob.get_size() self.doc._setObject(id_name, blob) results.append(info) if self.settings.widget == 'MULTI': current_files[id_name] = contenttype self.doc.setItem(self.fieldName, current_files) else: self.doc.setItem(self.fieldName, {id_name: contenttype}) if results: return results return False
def add(self, content): """Add the rule to the context """ storage = getUtility(IRuleStorage) chooser = INameChooser(storage) storage[chooser.chooseName(None, content)] = content
def add(self, **data): officelocation = OfficeLocation(**data) name = INameChooser(self.context).chooseName(u'', officelocation) self.context[name] = officelocation self.redirect(self.url(self.context))
def add(self, level): container = self.getContent() name = INameChooser(container).chooseName('', level) container[name] = level
def _initAssignmentNode(self, node): """Create an assignment from a node """ site = self.environ.getSite() # 1. Determine the assignment mapping and the name manager = node.getAttribute('manager') category = node.getAttribute('category') key = node.getAttribute('key') # convert unicode to str as unicode paths are not allowed in # restrictedTraverse called in assignment_mapping_from_key key = key.encode() purge = False if node.hasAttribute('purge'): purge = self._convertToBoolean(node.getAttribute('purge')) mapping = assignment_mapping_from_key(site, manager, category, key, create=True) # 2. Either find or create the assignment assignment = None name = node.getAttribute('name') if name: name = str(name) assignment = mapping.get(name, None) __traceback_info__ = "Assignment name: " + name if node.hasAttribute('remove'): if assignment is not None: del mapping[name] return if purge: for portlet in mapping.keys(): del mapping[portlet] return type_ = str(node.getAttribute('type')) if assignment is None: portlet_factory = getUtility(IFactory, name=type_) assignment = portlet_factory() if not name: chooser = INameChooser(mapping) name = chooser.chooseName(None, assignment) mapping[name] = assignment # aq-wrap it so that complex fields will work assignment = assignment.__of__(site) # set visibility setting visible = node.getAttribute('visible') if visible: settings = IPortletAssignmentSettings(assignment) settings['visible'] = self._convertToBoolean(visible) # 3. Use an adapter to update the portlet settings portlet_interface = getUtility(IPortletTypeInterface, name=type_) assignment_handler = IPortletAssignmentExportImportHandler(assignment) assignment_handler.import_assignment(portlet_interface, node) # 4. Handle ordering insert_before = node.getAttribute('insert-before') if insert_before: position = None keys = list(mapping.keys()) if insert_before == "*": position = 0 elif insert_before in keys: position = keys.index(insert_before) if position is not None: keys.remove(name) keys.insert(position, name) mapping.updateOrder(keys)
def __getattribute__(self, name): if name.startswith('_') or name.startswith( 'portal_') or name.startswith( '@@') or name == 'sql_id' or name in SpecificAttrs: return super(SQLDexterityItem, self).__getattribute__(name) connection = queryUtility(ISQLConnectionsUtility, name=self.portal_type, default=None) if connection == None and self.portal_type: fti = queryUtility(IDexterityFTI, name=self.portal_type, default=None) if not fti: return None updateConnectionsForFti(fti) connection = queryUtility(ISQLConnectionsUtility, name=self.portal_type, default=None) if name == 'view': #be sure session and sqlitem are up to date self._v_sql_item = None connection.session.close() if not connection: return super(SQLDexterityItem, self).__getattribute__(name) if name == 'UID' and self.sql_virtual: return self.portal_type + '-' + connection.sql_table + '-' + str( self.sql_id) if name == 'id' and 'id' not in connection.fieldnames.keys(): if not self.sql_virtual: return super(SQLDexterityItem, self).__getattribute__(name) fti = ISQLTypeSettings( getUtility(IDexterityFTI, name=self.portal_type)) nameFromTitle = INameFromTitle(self, None) if nameFromTitle is not None and nameFromTitle.title: sql_folder_id = getattr(fti, 'sql_folder_id', 'data-' + self.portal_type) title = nameFromTitle.title folder = None if IRelationValue.providedBy(sql_folder_id): folder = sql_folder_id.to_object elif sql_folder_id and sql_folder_id.startswith('/'): portal = getToolByName(getSite(), 'portal_url').getPortalObject() folder = portal.restrictedTraverse(sql_folder_id) if folder: name = INameChooser(folder).chooseName(title, self) return name # return INameChooser(getSite()).chooseName(title, self) # return getUtility(IURLNormalizer).normalize(title) return self.sql_id if name in connection.fieldnames.keys(): sql_column = connection.fieldnames[name] sql_item = self.getSQLItem() try: sql_id = getattr(sql_item, connection.sql_id_column, None) except orm_exc.DetachedInstanceError: self._v_sql_item = None sql_item = self.getSQLItem() sql_id = getattr(sql_item, connection.sql_id_column, None) fieldname = 'name' if sql_item and sql_column: while '.' in sql_column: sql_key = sql_column.split('.')[0] sql_item = getattr(sql_item, sql_key, None) if isinstance(sql_item, list): value = sql_item fieldname = sql_column.split('.')[-1] break sql_column = '.'.join(sql_column.split('.')[1:]) else: if not isinstance(sql_item, list): value = getattr(sql_item, sql_column, None) if not value and (isinstance(value, list) or hasattr(value, '_sa_instance_state')): value = '' elif (isinstance(value, list) or hasattr(value, '_sa_instance_state')): sqlftis = [ a for a in getAllUtilitiesRegisteredFor(IDexterityFTI) if 'collective.behavior.sql.behavior.behaviors.ISQLContent' in a.behaviors and getattr(a, 'sql_table', None) ] if name == 'subject': return tuple( [getattr(a, fieldname, '') for a in value]) tableftis = [] for iface in iterSchemataForType(self.portal_type): if name in iface.names(): field = iface[name] if IRelationChoice.providedBy( field) or IRelationList.providedBy(field): if IRelationChoice.providedBy(field): allowed_types = field.source.query.get( 'portal_type', []) else: allowed_types = field.value_type.source.query.get( 'portal_type', []) tableftis = [] for sqlfti in sqlftis: adapted = ISQLTypeSettings(sqlfti, None) if isinstance(value, list): classname = value[0].__class__.__name__ else: classname = value.__class__.__name__ if adapted and getattr( adapted, 'sql_table', None) == classname: if not allowed_types or sqlfti.id in allowed_types: tableftis.append(adapted) catalog = getToolByName( getSite(), 'portal_catalog') relations = [] for tablefti in tableftis: sql_id_column = getattr( tablefti, 'sql_id_column', 'id') valueids = [] if isinstance(value, list): valueids = [ getattr(a, sql_id_column, None) for a in value if getattr(a, sql_id_column, None) ] else: valueids = getattr( value, sql_id_column, None) valueids = [str(a) for a in valueids] brains = catalog.unrestrictedSearchResults( portal_type=tablefti.id, sql_id=valueids) for brain in brains: relations.append( SQLRelationValue( brain.portal_type, brain.UID, self)) if IRelationChoice.providedBy( field) and relations: return relations[0] elif IRelationList.providedBy( field) and relations: return relations elif ITuple.providedBy(field): return tuple( [getattr(a, fieldname, '') for a in value]) elif IList.providedBy(field): return [ getattr(a, fieldname, '') for a in value ] elif value and isinstance(value, list): value = getattr(value[0], fieldname, '') for iface in iterSchemataForType(self.portal_type): if name == 'subject': try: return tuple([ a.decode('utf-8') for a in literal_eval(value) ]) except: return tuple([a.strip() for a in value.split(',')]) if name in iface.names(): field = iface[name] if IRichText.providedBy(field): if not value: value = '' if not '<p' in value or not '<br' in value: value = '<p>' + '</p><p>'.join([ a for a in value.split('\n') if a.strip() ]) + '</p>' # try: # value = str(value) # except: # try: # value = value.decode('utf-8') # except: # try: # value = value.encode('utf-8') # except: # pass return RichTextValue(unidecode(value)) elif INamedBlobImage.providedBy(field): return NamedBlobImage( base64.b64decode(value), filename=unicode(self.portal_type + self.id + ".jpg")) elif ITuple.providedBy(field): if not value: return tuple([]) try: return tuple([ a.decode('utf-8') for a in literal_eval(value) ]) except: return tuple( [a.strip() for a in value.split(',')]) elif IList.providedBy(field): if not value: return [] try: return [ a.decode('utf-8') for a in literal_eval(value) ] except: return [a.strip() for a in value.split(',')] elif IDatetime.providedBy(field) and hasattr( value, 'day') and not hasattr(value, 'hour'): value = datetime.datetime.combine( value, datetime.datetime.min.time()) if name in [ 'expiration_date', 'effective_date', 'effective', 'expires' ] and hasattr(value, 'day') and not hasattr(value, 'hour'): value = datetime.datetime.combine( value, datetime.datetime.min.time()) if isinstance(value, unicode) or name == 'id': try: value = str(value) except: pass return value return super(SQLDexterityItem, self).__getattribute__(name)
def __getattribute__(self, name): if name.startswith('_') or name.startswith( 'portal_') or name.startswith('@@'): return super(SQLDexterityItem, self).__getattribute__(name) if name == 'id' and not self.sql_virtual: return super(SQLDexterityItem, self).__getattribute__(name) connection = queryUtility(ISQLConnectionsUtility, name=self.portal_type, default=None) if connection == None and self.portal_type: fti = queryUtility(IDexterityFTI, name=self.portal_type, default=None) if not fti: return None updateConnectionsForFti(fti) connection = queryUtility(ISQLConnectionsUtility, name=self.portal_type, default=None) if not connection: return super(SQLDexterityItem, self).__getattribute__(name) if name == 'UID': return self.portal_type + '-' + connection.sql_table + '-' + str( self.sql_id) if name == 'id' and 'id' not in connection.fieldnames.keys(): fti = ISQLTypeSettings( getUtility(IDexterityFTI, name=self.portal_type)) nameFromTitle = INameFromTitle(self, None) if nameFromTitle is not None and nameFromTitle.title: sql_folder_id = getattr(fti, 'sql_folder_id', 'data-' + self.portal_type) title = nameFromTitle.title if IRelationValue.providedBy(name): folder = sql_folder_id.to_object if folder: return INameChooser(folder).chooseName(title, self) return INameChooser(getSite()).chooseName(title, self) if name in connection.fieldnames.keys(): sql_column = connection.fieldnames[name] sql_item = self.getSQLItem() fieldname = 'name' if sql_item and sql_column: while '.' in sql_column: sql_item = getattr(sql_item, sql_column.split('.')[0], None) if sql_item and ( (isinstance(sql_item, list) and len(sql_item) > 1) or hasattr(sql_item, '_sa_instance_state')): value = sql_item fieldname = sql_column.split('.')[-1] break sql_column = '.'.join(sql_column.split('.')[1:]) else: value = getattr(sql_item, sql_column, None) #this is a relation if value and (isinstance(value, list) or hasattr(value, '_sa_instance_state')): sqlftis = [ a for a in getAllUtilitiesRegisteredFor(IDexterityFTI) if 'collective.behavior.sql.behavior.behaviors.ISQLContent' in a.behaviors and getattr(a, 'sql_table', None) ] if name == 'subject': return tuple( [getattr(a, fieldname, '') for a in value]) tableftis = [] for iface in iterSchemataForType(self.portal_type): if name in iface.names(): field = iface[name] if IList.providedBy(field): return [ getattr(a, fieldname, '') for a in value ] # hope it has name! elif ITuple.providedBy(field): return tuple( [getattr(a, fieldname, '') for a in value]) if IRelationChoice.providedBy( field) or IRelationList.providedBy(field): if IRelationChoice.providedBy(field): allowed_types = field.source.query.get( 'portal_type', []) else: allowed_types = field.value_type.source.query.get( 'portal_type', []) tableftis = [] for sqlfti in sqlftis: adapted = ISQLTypeSettings(sqlfti, None) if isinstance(value, list): classname = value[0].__class__.__name__ else: classname = value.__class__.__name__ if adapted and getattr( adapted, 'sql_table', None) == classname: if not allowed_types or sqlfti.id in allowed_types: tableftis.append(adapted) catalog = getToolByName( getSite(), 'portal_catalog') relations = [] for tablefti in tableftis: sql_id_column = getattr( tablefti, 'sql_id_column', 'id') valueids = [] if isinstance(value, list): valueids = [ getattr(a, sql_id_column, None) for a in value if getattr(a, sql_id_column, None) ] else: valueids = getattr( value, sql_id_column, None) brains = catalog.searchResults( portal_type=tablefti.id, sql_id=valueids) for brain in brains: relations.append( SQLRelationValue( brain.portal_type, brain.sql_id)) if IRelationChoice.providedBy( field) and relations: return relations[0] elif IRelationList.providedBy( field) and relations: return relations for iface in iterSchemataForType(self.portal_type): if name == 'subject': try: return tuple([ a.decode('utf-8') for a in literal_eval(value) ]) except: return tuple([a.strip() for a in value.split(',')]) if name in iface.names(): field = iface[name] if IRichText.providedBy(field): return RichTextValue(value) if INamedBlobImage.providedBy(field): return NamedBlobImage( base64.b64decode(value), filename=unicode(self.portal_type + self.id + ".jpg")) if IList.providedBy(field): try: return [ a.decode('utf-8') for a in literal_eval(value) ] except: return [a.strip() for a in value.split(',')] if ITuple.providedBy(field): try: return tuple([ a.decode('utf-8') for a in literal_eval(value) ]) except: return tuple( [a.strip() for a in value.split(',')]) if isinstance(value, unicode) or name == 'id': try: return str(value) except: pass return value return super(SQLDexterityItem, self).__getattribute__(name)
def test_downtimeTimezones(self, _getUtcnow): # Execute a browser test for downtime to ensure correct time formats and # timezone handling. # Hack to be able to mock utcnow as it can not be patched immediatelly as it is # member of the builtin type datetime. Additionally datetime is required by Plone # within the patching scope. _getUtcnow.return_value = datetime.datetime(2017, 4, 13, 15, 37, 0, 0, pytz.utc) # Allow user create content. setRoles(self.portal, TEST_USER_ID, [ 'Manager', ]) # Create the provider folder and two providers. self.portal.invokeFactory('Folder', 'Providers') self.portal.Providers.invokeFactory('Provider', 'provider') self.portal.Providers.invokeFactory('Provider', self.TEST_OTHER_PROVIDER) # Create primary providers downtime to be filled out via browser. self.portal.Providers.provider.invokeFactory('Downtime', 'downtime') # Setup default workflow. getToolByName(self.portal, 'portal_workflow').setDefaultChain('intranet_workflow') # Setup downtime portlet. column = getUtility(IPortletManager, 'plone.leftcolumn') manager = getMultiAdapter((self.portal, column), IPortletAssignmentMapping) assignment = Assignment() chooser = INameChooser(manager) setRoles(self.portal, TEST_USER_ID, [ 'Manager', ]) manager[chooser.chooseName(None, assignment)] = assignment # Setup secondary provider and it's downtimes: # * otherDowntime: not to be shown by portlet in primary provider's content subtree # * pastDowntime: not to be shown by portlet at all otherProvider = self.portal.Providers[self.TEST_OTHER_PROVIDER] otherProvider.update(title=self.TEST_OTHER_PROVIDER) otherProvider.invokeFactory('Downtime', self.TEST_OTHER_DOWNTIME) otherDowntime = otherProvider[self.TEST_OTHER_DOWNTIME] otherDowntime.update(title=self.TEST_OTHER_DOWNTIME, startDateTime=self.TEST_OTHER_DOWNTIME_START, endDateTime=self.TEST_OTHER_DOWNTIME_END) otherProvider.invokeFactory('Downtime', self.TEST_PAST_DOWNTIME) pastDowntime = otherProvider[self.TEST_PAST_DOWNTIME] pastDowntime.update(title=self.TEST_PAST_DOWNTIME, startDateTime=self.TEST_PAST_DOWNTIME_START, endDateTime=self.TEST_PAST_DOWNTIME_END) plone.api.content.transition(obj=otherDowntime, transition='publish') plone.api.content.transition(obj=pastDowntime, transition='publish') transaction.commit() # Start actual interaction via browser from plone.testing.z2 import Browser browser = Browser(self.app) browser.handleErrors = False portal_url = self.portal.absolute_url() self.portal.error_log._ignored_exceptions = () browser.open(portal_url + '/login_form') browser.getControl(name='__ac_name').value = TEST_USER_NAME browser.getControl(name='__ac_password').value = TEST_USER_PASSWORD browser.getControl(name='submit').click() self.assertIn('You are now logged in', browser.contents) browser.open(portal_url) # Create provider browser.follow('Providers') browser.follow('Add new') self.assertTrue('Add new item' in browser.contents) self.assertTrue('Compute or data service provider' in browser.contents) browser.getControl("Provider").click() browser.getControl(name='form.button.Add').click() browser.getControl(name="title").value = self.TEST_PROVIDER_NAME browser.getControl( name='provider_userid').value = self.TEST_PROVIDER_ID browser.getControl(name='address.city:record:ignore_empty' ).value = self.TEST_PROVIDER_CITY browser.getControl( name='address.country:record:ignore_empty').displayValue = [ self.TEST_PROVIDER_COUNTRY ] browser.getControl(name="form.button.save").click() # Create downtime browser.follow('Add new') self.assertTrue('Add new item' in browser.contents) browser.getControl(label='Downtime').click() browser.getControl(name='form.button.Add').click() self.assertTrue('Add Downtime' in browser.contents) browser.getControl(name='title').value = self.TEST_DOWNTIME_TITLE browser.getControl( name='description').value = self.TEST_DOWNTIME_DESCRIPTION self.fillInDateWidget(browser, 'startDateTime', self.TEST_DOWNTIME_START) self.fillInDateWidget(browser, 'endDateTime', self.TEST_DOWNTIME_END) browser.getControl(name='form.button.save').click() # Publish browser.follow('Publish') browser.getControl(name='form.button.confirm').click() # Check detail view self.assertContainsDowntimeFull(browser) # Check overview browser.open(portal_url + '/downtime_overview') self.assertContainsDowntimeShort(browser) # Back to detail view and edit browser.follow('Das ganze Schei') browser.follow('Edit') # Check edit view for correct dates self.assertDateWidget(browser, 'startDateTime', self.TEST_DOWNTIME_START) self.assertDateWidget(browser, 'endDateTime', self.TEST_DOWNTIME_END) # Check portlet on portal site browser.open(portal_url) self.assertTrue('All Downtimes...' in browser.contents) self.assertContainsDowntimeShort(browser) self.assertFalse( re.search('Upcoming Downtimes\\s+?\\(' + self.TEST_PROVIDER_NAME, browser.contents)) self.assertTrue(self.TEST_OTHER_DOWNTIME in browser.contents) self.assertFalse(self.TEST_PAST_DOWNTIME in browser.contents) # Check portlet on provider overview site browser.follow('Providers') self.assertContainsDowntimeShort(browser) self.assertFalse( re.search('Upcoming Downtimes\\s+?\\(' + self.TEST_PROVIDER_NAME, browser.contents)) self.assertTrue(self.TEST_OTHER_DOWNTIME in browser.contents) self.assertFalse(self.TEST_PAST_DOWNTIME in browser.contents) # Check portlet on provider detail site browser.follow(self.TEST_PROVIDER_NAME) self.assertContainsDowntimeShort(browser) self.assertTrue( re.search('Upcoming Downtimes\\s+?\\(' + self.TEST_PROVIDER_NAME, browser.contents)) self.assertFalse(self.TEST_OTHER_DOWNTIME in browser.contents) self.assertFalse(self.TEST_PAST_DOWNTIME in browser.contents)
def ical_import(container, ics_resource, event_type): cal = icalendar.Calendar.from_ical(ics_resource) events = cal.walk('VEVENT') def _get_prop(prop, item): ret = None if prop in item: ret = safe_unicode(item.decoded(prop)) return ret def _from_list(ical, prop): """For EXDATE and RDATE recurrence component properties, the dates can be defined within one EXDATE/RDATE line or for each date an individual line. In the latter case, icalendar creates a list. This method handles this case. TODO: component property parameters like TZID are not used here. """ val = prop in ical and ical[prop] or [] if not isinstance(val, list): val = [val] #ret = '' #for item in val: # ret = ret and '%s\n' % ret or ret # insert linebreak # ret = '%s%s:%s' % (ret, prop, item.to_ical()) #return ret # Zip multiple lines into one, since jquery.recurrenceinput.js does # not support multiple lines here # https://github.com/collective/jquery.recurrenceinput.js/issues/15 ret = '' for item in val: ret = ret and '%s,' % ret or ret # insert linebreak ret = '%s%s' % (ret, item.to_ical()) return ret and '%s:%s' % (prop, ret) or None count = 0 for item in events: start = _get_prop('DTSTART', item) end = _get_prop('DTEND', item) if not end: duration = _get_prop('DURATION', item) if duration: end = start + duration # else: whole day or open end timezone = getattr(getattr(start, 'tzinfo', None), 'zone', None) or\ base.default_timezone(container) whole_day = False open_end = False if is_date(start) and (is_date(end) or end is None): # All day / whole day events # End must be same type as start (RFC5545, 3.8.2.2) whole_day = True if end is None: end = start if start < end: # RFC5545 doesn't define clearly, if all day events should have # a end date one day after the start day at 0:00. # Internally, we handle all day events with start=0:00, # end=:23:59:59, so we substract one day here. end = end - datetime.timedelta(days=1) start = base.dt_start_of_day(date_to_datetime(start)) end = base.dt_end_of_day(date_to_datetime(end)) elif is_datetime(start) and end is None: # Open end event, see RFC 5545, 3.6.1 open_end = True end = base.dt_end_of_day(date_to_datetime(start)) assert(is_datetime(start)) assert(is_datetime(end)) title = _get_prop('SUMMARY', item) description = _get_prop('DESCRIPTION', item) location = _get_prop('LOCATION', item) url = _get_prop('URL', item) rrule = _get_prop('RRULE', item) rrule = rrule and 'RRULE:%s' % rrule.to_ical() or '' rdates = _from_list(item, 'RDATE') exdates = _from_list(item, 'EXDATE') rrule = '\n'.join([it for it in [rrule, rdates, exdates] if it]) # TODO: attendee-lists are not decoded properly and contain only # vCalAddress values attendees = _get_prop('ATTENDEE', item) contact = _get_prop('CONTACT', item) categories = _get_prop('CATEGORIES', item) if hasattr(categories, '__iter__'): categories = [safe_unicode(it) for it in categories] # for sync created = _get_prop('CREATED', item) modified = _get_prop('LAST-MODIFIED', item) # TODO: better use plone.api, from which some of the code here is # copied content_id = str(random.randint(0, 99999999)) # TODO: if AT had the same attrs like IDXEventBase, we could set # everything within this invokeFactory call. container.invokeFactory(event_type, id=content_id, title=title, description=description) content = container[content_id] event = IEventAccessor(content) event.start = start event.end = end event.timezone = timezone event.whole_day = whole_day event.open_end = open_end event.location = location event.event_url = url event.recurrence = rrule event.attendees = attendees event.contact_name = contact event.subjects = categories notify(ObjectModifiedEvent(content)) # Archetypes specific code if getattr(content, 'processForm', False): # Will finish Archetypes content item creation process, # rename-after-creation and such content.processForm() if content_id in container: # Rename with new id from title, if processForm didn't do it. chooser = INameChooser(container) new_id = chooser.chooseName(title, content) transaction.savepoint(optimistic=True) # Commit before renaming content.aq_parent.manage_renameObject(content_id, new_id) else: transaction.savepoint(optimistic=True) count += 1 return {'count': count}
def get_new_id(self, obj): return INameChooser(self.context).chooseName(None, obj)
def create_object(self, folder, type_, info): filename = info['name'] name = filename.decode("utf8") chooser = INameChooser(folder) chooser_name = name.lower().replace('aq_', '') newid = chooser.chooseName(chooser_name, folder.aq_parent) # strip metadata from file if (type_ in ('Image', 'File', 'Video') and exiftool is not None and 'tmp_file' in info): is_pdf = ('application/pdf' in guess_type(info['tmp_file'])) if is_pdf and qpdf is not None: try: # Will recursively remove the tags of the file using exiftool, linearize it. # And do it again. exiftool(info['tmp_file']) qpdf(info['tmp_file']) exiftool(info['tmp_file']) qpdf(info['tmp_file']) except Exception: logger.warn('Could not strip additional metadata with qpdf %s' % info['tmp_file']) else: try: exiftool(info['tmp_file']) except Exception: logger.warn('Could not strip metadata from file: %s' % info['tmp_file']) fi = open(info['tmp_file'], 'r') try: # Try to determine which kind of NamedBlob we need # This will suffice for standard p.a.contenttypes File/Image # and any other custom type that would have 'File' or 'Image' in # its type name filename = ploneutils.safe_unicode(filename) create_opts = dict( type=type_, id=newid, container=folder) if 'Image' in type_: image = NamedBlobImage(data=fi, filename=filename) try: image.focal_point = [ float(self.request.form.get('focalX')), float(self.request.form.get('focalY')) ] except Exception: pass create_opts['image'] = image else: create_opts['file'] = NamedBlobFile(data=fi, filename=filename) for field in get_upload_fields(): if not field.get('name'): continue name = field['name'] if not self.request.form.get(name): continue if name in ('tags', 'subject'): # tags needs to be converted create_opts['subject'] = self.request.form.get(name).split(';') else: create_opts[name] = self.request.form.get(name, '') return api.content.create(**create_opts) finally: fi.close()
def convert_legacy_portlets(context): """Convert legacy portlets (left_slots, right_slots) in the given context to new-style portlets. """ portletsMapping = { 'portlet_login': login.Assignment(), 'portlet_news': news.Assignment(count=5), 'portlet_navigation': navigation.Assignment(), 'portlet_review': review.Assignment(), 'portlet_recent': recent.Assignment(count=5), 'portlet_related': DONT_MIGRATE, 'portlet_languages': DONT_MIGRATE, } if HAS_EVENTS: portletsMapping.update({ 'portlet_calendar': portlet_calendar.Assignment(), 'portlet_events': portlet_events.Assignment(count=5), }) # Convert left_slots and right_slots to portlets left = getUtility(IPortletManager, name='plone.leftcolumn') right = getUtility(IPortletManager, name='plone.rightcolumn') leftAssignable = getMultiAdapter((context, left), IPortletAssignmentMapping).__of__(context) rightAssignable = getMultiAdapter( (context, right), IPortletAssignmentMapping).__of__(context) IPortletPermissionChecker(leftAssignable)() IPortletPermissionChecker(rightAssignable)() leftChooser = INameChooser(leftAssignable) rightChooser = INameChooser(rightAssignable) left_slots = getattr(aq_base(context), 'left_slots', []) right_slots = getattr(aq_base(context), 'right_slots', []) for item in left_slots: path = item.split('/') if len(path) == 4: newPortlet = portletsMapping.get(path[1], None) if newPortlet is None and path[0] in ( 'context', 'here') and path[2] == 'macros': newPortlet = classic.Assignment(path[1], path[3]) if newPortlet is not None and newPortlet is not DONT_MIGRATE: leftAssignable[leftChooser.chooseName(None, newPortlet)] = newPortlet for item in right_slots: path = item.split('/') if len(path) == 4: newPortlet = portletsMapping.get(path[1], None) if newPortlet is None and path[0] in ( 'context', 'here') and path[2] == 'macros': newPortlet = classic.Assignment(path[1], path[3]) if newPortlet is not None and newPortlet is not DONT_MIGRATE: rightAssignable[rightChooser.chooseName( None, newPortlet)] = newPortlet context.left_slots = [] context.right_slots = []
def addScoreSystem(self, target): chooser = INameChooser(self.context) name = chooser.chooseName('', target) self.context[name] = target
def add(self, schedule): chooser = INameChooser(self.context) name = chooser.chooseName('', schedule) self.context[name] = schedule self._object_added = schedule
def add(self, content): # I think this should be more deterministic name = INameChooser(self).chooseName(content.__name__ or '', content) self[name] = content
def register_portlets(obj, item): """Register portlets fror one object Code adapted from plone.app.portlets.exportimport.portlets.PortletsXMLAdapter Work in progress... """ site = api.portal.get() request = getRequest() results = 0 for manager_name, portlets in item.get("portlets", {}).items(): manager = getUtility(IPortletManager, manager_name) mapping = queryMultiAdapter((obj, manager), IPortletAssignmentMapping) namechooser = INameChooser(mapping) for portlet_data in portlets: # 1. Create the assignment assignment_data = portlet_data["assignment"] portlet_type = portlet_data["type"] portlet_factory = getUtility(IFactory, name=portlet_type) assignment = portlet_factory() name = namechooser.chooseName(None, assignment) mapping[name] = assignment logger.info("Added portlet {} to {}".format( name, obj.absolute_url())) # aq-wrap it so that complex fields will work assignment = assignment.__of__(site) # set visibility setting visible = portlet_data.get("visible") if visible: settings = IPortletAssignmentSettings(assignment) settings["visible"] = visible # 2. Apply portlet settings portlet_interface = getUtility(IPortletTypeInterface, name=portlet_type) for property_name, value in assignment_data.items(): field = portlet_interface.get(property_name, None) if field is None: continue field = field.bind(assignment) # deserialize data (e.g. for RichText) deserializer = queryMultiAdapter((field, obj, request), IFieldDeserializer) if deserializer is not None: try: value = deserializer(value) except Exception as e: logger.info( u"Could not import portlet data {} for field {} on {}: {}" .format(value, field, obj.absolute_url(), str(e))) continue field.set(assignment, value) results += 1 for blacklist_status in item.get("blacklist_status", []): status = blacklist_status["status"] manager_name = blacklist_status["manager"] category = blacklist_status["category"] manager = getUtility(IPortletManager, manager_name) assignable = queryMultiAdapter((obj, manager), ILocalPortletAssignmentManager) if status.lower() == "block": assignable.setBlacklistStatus(category, True) elif status.lower() == "show": assignable.setBlacklistStatus(category, False) return results
def add(self, timetable): """Add the timetable to self.context.""" nameChooser = INameChooser(self.context) key = nameChooser.chooseName('', timetable) self.context[key] = timetable
def __call__(self): self.errors = [] self.protect() context = aq_inner(self.context) catalog = getToolByName(context, 'portal_catalog') mtool = getToolByName(context, 'portal_membership') missing = [] for key in self.request.form.keys(): if not key.startswith('UID_'): continue index = key.split('_')[-1] uid = self.request.form[key] brains = catalog(UID=uid, show_inactive=True) if len(brains) == 0: missing.append(uid) continue obj = brains[0].getObject() title = self.objectTitle(obj) if not mtool.checkPermission('Copy or Move', obj): self.errors.append( _(u'Permission denied to rename ${title}.', mapping={u'title': title})) continue sp = transaction.savepoint(optimistic=True) newid = self.request.form['newid_' + index] if six.PY2: newid = newid.encode('utf8') newtitle = self.request.form['newtitle_' + index] try: obid = obj.getId() title = obj.Title() change_title = newtitle and title != newtitle if change_title: getSecurityManager().validate(obj, obj, 'setTitle', obj.setTitle) obj.setTitle(newtitle) notify(ObjectModifiedEvent(obj)) if newid and obid != newid: parent = aq_parent(aq_inner(obj)) # Make sure newid is safe newid = INameChooser(parent).chooseName(newid, obj) # Update the default_page on the parent. context_state = getMultiAdapter((obj, self.request), name='plone_context_state') if context_state.is_default_page(): parent.setDefaultPage(newid) parent.manage_renameObjects((obid, ), (newid, )) elif change_title: # the rename will have already triggered a reindex obj.reindexObject() except ConflictError: raise except Exception as e: sp.rollback() if six.PY2: title = title.decode('utf8') logger.error(u'Error renaming "{title}": "{exception}"'.format( title=title, exception=e)) self.errors.append( _(u'Error renaming ${title}', mapping={'title': title})) return self.message(missing)
def __call__(self, name, content_type, data, title, request): # contextual import to prevent ImportError from plone.dexterity.utils import createContentInContainer ctr = getToolByName(self.context, 'content_type_registry') type_ = ctr.findTypeName(name.lower(), '', '') or 'File' name = name.decode('utf8') title = title.decode('utf8') chooser = INameChooser(self.context) # otherwise I get ZPublisher.Conflict ConflictErrors # when uploading multiple files upload_lock.acquire() def trim_title(title): pview = getMultiAdapter((self.context, request), name='plone') return pview.cropText(title, 40) if title: newid = chooser.chooseName(title, self.context.aq_parent) else: newid = chooser.chooseName(name, self.context.aq_parent) try: transaction.begin() # Try to determine which kind of NamedBlob we need # This will suffice for standard p.a.contenttypes File/Image # and any other custom type that would have 'File' or 'Image' in # its type name if 'File' in type_: file = NamedBlobFile(data=data.read(), filename=unicode(data.filename), contentType=content_type) obj = createContentInContainer(self.context, 'AppFile', id=newid, title=trim_title(title), description=title, file=file, checkConstraints=False) elif 'Image' in type_: image = NamedBlobImage(data=data.read(), filename=unicode(data.filename), contentType=content_type) obj = createContentInContainer(self.context, 'AppImage', id=newid, title=trim_title(title), description=title, image=image, checkConstraints=False) # obj.title = name obj.reindexObject() transaction.commit() finally: upload_lock.release() return obj
def folderupload(self, files, title='', description=''): if not self.doc.isDocument(): return self.doc.setfile(self.doc, files[0]) docfolderId = self.doc.getId() dbfolderId = self.doc.getParentDatabase().id #TODO come configurare diverse cartelle per applicazione o plomino db (da fare sulle singole app)? target = self.context.portal_url.getPortalObject()[ATTACHMENT_FOLDER] with adopt_roles('Manager'): if not dbfolderId in target.keys(): target.invokeFactory("Folder", id=dbfolderId, title=dbfolderId) target = target[dbfolderId] if not docfolderId in target.keys(): target.invokeFactory("Folder", id=docfolderId, title=docfolderId) docFolder = target[docfolderId] for username, roles in self.doc.get_local_roles(): docFolder.manage_setLocalRoles(username, roles) if not isinstance(files, list): files = [files] #se non campo multiplo vuoto la cartella #TODO tenere allineati i files nella cartella con i nomi sul campo di plomino current_files = self.doc.getItem(self.element) cleaned_files = {} if self.multiple: for fName in current_files: if fName in docFolder.keys(): cleaned_files[fName] = current_files[fName] self.doc.setItem(self.element, cleaned_files) #se upload singolo cancello tutti i file presenti collegati al campo else: try: docFolder.manage_delObjects(current_files.keys()) except Exception as error: pass self.doc.removeItem(self.element) namechooser = INameChooser(docFolder) loaded = [] for item in files: if item.filename: content_type = item.headers.get('Content-Type') filename = safe_unicode(item.filename) data = item.read() id_name = '' title = title and title[0] or filename # Get a unique id here id_name = namechooser.chooseName(title, docFolder) # Portal types allowed : File and Image # Since Plone 4.x both types use Blob if content_type in IMAGE_MIMETYPES: portal_type = 'Image' wrapped_data = NamedBlobImage(data=data, filename=filename) else: portal_type = 'File' wrapped_data = NamedBlobFile(data=data, filename=filename) # Create content docFolder.invokeFactory(portal_type, id=id_name, title=title, description=description[0]) newfile = docFolder[id_name] # Set data if portal_type == 'File': if IATFile.providedBy(newfile): newfile.setFile(data, filename=filename) else: newfile.file = wrapped_data elif portal_type == 'Image': if IATImage.providedBy(newfile): newfile.setImage(data, filename=filename) else: newfile.image = wrapped_data # Finalize content creation, reindex it newfile.reindexObject() notify(ObjectModifiedEvent(newfile)) loaded.append(newfile) if loaded: return loaded return False
def addItem(self, item): chooser = INameChooser(self) item_id = getattr(item, 'ldap_name', None) or chooser.chooseName( None, item) self[item_id] = item
def add(self, content): name = INameChooser(self).chooseName(content.__name__ or '', content) self[name] = content
def ical_import(container, ics_resource, event_type, sync_strategy=base.SYNC_KEEP_NEWER): cal = icalendar.Calendar.from_ical(ics_resource) events = cal.walk('VEVENT') cat = getToolByName(container, 'portal_catalog') container_path = '/'.join(container.getPhysicalPath()) def _get_by_sync_uid(uid): return cat(sync_uid=uid, path={'query': container_path, 'depth': 1}) def _get_prop(prop, item, default=None): ret = default if prop in item: ret = safe_unicode(item.decoded(prop)) return ret def _from_list(ical, prop): """For EXDATE and RDATE recurrence component properties, the dates can be defined within one EXDATE/RDATE line or for each date an individual line. In the latter case, icalendar creates a list. This method handles this case. TODO: component property parameters like TZID are not used here. """ val = prop in ical and ical[prop] or [] if not isinstance(val, list): val = [val] #ret = '' #for item in val: # ret = ret and '%s\n' % ret or ret # insert linebreak # ret = '%s%s:%s' % (ret, prop, item.to_ical()) #return ret # Zip multiple lines into one, since jquery.recurrenceinput.js does # not support multiple lines here # https://github.com/collective/jquery.recurrenceinput.js/issues/15 ret = '' for item in val: ret = ret and '%s,' % ret or ret # insert linebreak ret = '%s%s' % (ret, item.to_ical()) return ret and '%s:%s' % (prop, ret) or None count = 0 for item in events: start = _get_prop('DTSTART', item) end = _get_prop('DTEND', item) if not end: duration = _get_prop('DURATION', item) if duration: end = start + duration # else: whole day or open end timezone = getattr(getattr(start, 'tzinfo', None), 'zone', None) or\ base.default_timezone(container) whole_day = False open_end = False if is_date(start) and (is_date(end) or end is None): # All day / whole day events # End must be same type as start (RFC5545, 3.8.2.2) whole_day = True if end is None: end = start if start < end: # RFC5545 doesn't define clearly, if all day events should have # a end date one day after the start day at 0:00. # Internally, we handle all day events with start=0:00, # end=:23:59:59, so we substract one day here. end = end - datetime.timedelta(days=1) start = base.dt_start_of_day(date_to_datetime(start)) end = base.dt_end_of_day(date_to_datetime(end)) elif is_datetime(start) and end is None: # Open end event, see RFC 5545, 3.6.1 open_end = True end = base.dt_end_of_day(date_to_datetime(start)) assert (is_datetime(start)) assert (is_datetime(end)) title = _get_prop('SUMMARY', item) description = _get_prop('DESCRIPTION', item) location = _get_prop('LOCATION', item) url = _get_prop('URL', item) rrule = _get_prop('RRULE', item) rrule = rrule and 'RRULE:%s' % rrule.to_ical() or '' rdates = _from_list(item, 'RDATE') exdates = _from_list(item, 'EXDATE') rrule = '\n'.join([it for it in [rrule, rdates, exdates] if it]) # TODO: attendee-lists are not decoded properly and contain only # vCalAddress values attendees = item.get('ATTENDEE', ()) contact = _get_prop('CONTACT', item) categories = item.get('CATEGORIES', ()) if hasattr(categories, '__iter__'): categories = [safe_unicode(it) for it in categories] ext_modified = utc(_get_prop('LAST-MODIFIED', item)) # TODO: better use plone.api for content creation, from which some of # the code here is copied content = None new_content_id = None existing_event = None sync_uid = _get_prop('UID', item) if sync_strategy != base.SYNC_NONE and sync_uid: existing_event = _get_by_sync_uid(sync_uid) if existing_event: if sync_strategy == base.SYNC_KEEP_MINE: # On conflict, keep mine continue exist_event = existing_event[0].getObject() acc = IEventAccessor(exist_event) if sync_strategy == base.SYNC_KEEP_NEWER and\ (not ext_modified or acc.last_modified >= ext_modified): # Update only, if newer, if ext_modified exists continue # Else: update content = exist_event else: # TODO: if AT had the same attrs like IDXEventBase, we could set # everything within this invokeFactory call. new_content_id = str(random.randint(0, 99999999)) container.invokeFactory(event_type, id=new_content_id, title=title, description=description) content = container[new_content_id] assert (content) # At this point, a content must be available. event = IEventAccessor(content) event.title = title event.description = description event.start = start event.end = end event.timezone = timezone event.whole_day = whole_day event.open_end = open_end event.location = location event.event_url = url event.recurrence = rrule event.attendees = attendees event.contact_name = contact event.subjects = categories if sync_strategy != base.SYNC_NONE: # Don't import the sync_uid, if no sync strategy is chosen. Let the # sync_uid be autogenerated then. event.sync_uid = sync_uid notify(ObjectModifiedEvent(content)) # Archetypes specific code if getattr(content, 'processForm', False): # Will finish Archetypes content item creation process, # rename-after-creation and such content.processForm() # Use commits instead of savepoints to avoid "FileStorageError: # description too long" on large imports. transaction.get().commit() # Commit before rename if new_content_id and new_content_id in container: # Rename with new id from title, if processForm didn't do it. chooser = INameChooser(container) new_id = chooser.chooseName(title, content) content.aq_parent.manage_renameObject(new_content_id, new_id) # Do this at the end, otherwise it's overwritten if ext_modified: event.last_modified = ext_modified count += 1 return {'count': count}
def add(self, ob): self.context[INameChooser(self.context).chooseName()] = ob
def _initRules(self, node): """Import rules from the given node """ site = self.environ.getSite() storage = queryUtility(IRuleStorage) if storage is None: return for child in node.childNodes: if child.nodeName == 'rule': rule = None name = child.getAttribute('name') if name: rule = storage.get(name, None) if rule is None: rule = Rule() if not name: chooser = INameChooser(storage) name = chooser.chooseName(None, rule) storage[name] = rule else: # Clear out conditions and actions since we're expecting # new ones del rule.conditions[:] del rule.actions[:] rule.title = child.getAttribute('title') rule.description = child.getAttribute('description') event_name = child.getAttribute('event') rule.event = _resolveDottedName(event_name) if not rule.event: raise ImportError('Can not import {0}'.format(event_name)) rule.enabled = as_bool(child.getAttribute('enabled'), True) rule.stop = as_bool(child.getAttribute('stop-after')) rule.cascading = as_bool(child.getAttribute('cascading')) # Aq-wrap to enable complex setters for elements below # to work rule = rule.__of__(site) for rule_config_node in child.childNodes: if rule_config_node.nodeName == 'conditions': for condition_node in rule_config_node.childNodes: if not condition_node.nodeName == 'condition': continue type_ = condition_node.getAttribute('type') element_type = getUtility(IRuleCondition, name=type_) if element_type.factory is None: continue condition = element_type.factory() # Aq-wrap in case of complex setters condition = condition.__of__(rule) handler = IRuleElementExportImportHandler( condition) handler.import_element(condition_node) rule.conditions.append(aq_base(condition)) elif rule_config_node.nodeName == 'actions': for action_node in rule_config_node.childNodes: if not action_node.nodeName == 'action': continue type_ = action_node.getAttribute('type') element_type = getUtility(IRuleAction, name=type_) if element_type.factory is None: continue action = element_type.factory() # Aq-wrap in case of complex setters action = action.__of__(rule) handler = IRuleElementExportImportHandler(action) handler.import_element(action_node) rule.actions.append(aq_base(action)) elif child.nodeName == 'assignment': location = child.getAttribute('location') if location.startswith('/'): location = location[1:] try: container = site.unrestrictedTraverse(str(location)) except KeyError: continue name = child.getAttribute('name') api.assign_rule( container, name, enabled=as_bool(child.getAttribute('enabled')), bubbles=as_bool(child.getAttribute('bubbles')), insert_before=child.getAttribute('insert-before'), )
def create( container=None, type=None, id=None, title=None, safe_id=False, **kwargs # NOQA: C816 ): """Create a new content item. :param container: [required] Container object in which to create the new object. :type container: Folderish content object :param type: [required] Type of the object. :type type: string :param id: Id of the object. If the id conflicts with another object in the container, a suffix will be added to the new object's id. If no id is provided, automatically generate one from the title. If there is no id or title provided, raise a ValueError. :type id: string :param title: Title of the object. If no title is provided, use id as the title. :type title: string :param safe_id: When False, the given id will be enforced. If the id is conflicting with another object in the target container, raise an InvalidParameterError. When True, choose a new, non-conflicting id. :type safe_id: boolean :returns: Content object :raises: KeyError, :class:`~plone.api.exc.MissingParameterError`, :class:`~plone.api.exc.InvalidParameterError` :Example: :ref:`content_create_example` """ # Create a temporary id if the id is not given content_id = not safe_id and id or str(random.randint(0, 99999999)) if title: kwargs['title'] = title try: container.invokeFactory(type, content_id, **kwargs) except UnicodeDecodeError: # UnicodeDecodeError is a subclass of ValueError, # so will be swallowed below unless we re-raise it here raise except ValueError as e: types = [fti.getId() for fti in container.allowedContentTypes()] raise InvalidParameterError( "Cannot add a '{obj_type}' object to the container.\n" 'Allowed types are:\n' '{allowed_types}\n' '{message}'.format( obj_type=type, allowed_types='\n'.join(sorted(types)), message=e.message, ), ) content = container[content_id] # Archetypes specific code if IBaseObject.providedBy(content): # Will finish Archetypes content item creation process, # rename-after-creation and such content.processForm(values=kwargs) if not id or (safe_id and id): # Create a new id from title chooser = INameChooser(container) derived_id = id or title new_id = chooser.chooseName(derived_id, content) # kacee: we must do a partial commit, else the renaming fails because # the object isn't in the zodb. # Thus if it is not in zodb, there's nothing to move. We should # choose a correct id when # the object is created. # maurits: tests run fine without this though. transaction.savepoint(optimistic=True) content.aq_parent.manage_renameObject(content_id, new_id) return content
def add_test_data(self, *items): from collective.notices.interfaces import INoticeFactory for item in items: self.storage[INameChooser(self.storage).chooseName()] = \ INoticeFactory(self.storage)(**item)