class ViewletSettingsStorage(Persistent): implements(IViewletSettingsStorage) def __init__(self): self._order = PersistentDict() self._hidden = PersistentDict() self._defaults = PersistentDict() def getOrder(self, name, skinname): skin = self._order.get(skinname, {}) order = skin.get(name, ()) if not order: skinname = self.getDefault(name) if skinname is not None: skin = self._order.get(skinname, {}) order = skin.get(name, ()) return order def setOrder(self, name, skinname, order): skin = self._order.setdefault(skinname, PersistentDict()) skin[name] = tuple(order) if self.getDefault(name) is None: self.setDefault(name, skinname) def getHidden(self, name, skinname): skin = self._hidden.get(skinname, {}) hidden = skin.get(name, ()) if not hidden: skinname = self.getDefault(name) if skinname is not None: skin = self._hidden.get(skinname, {}) hidden = skin.get(name, ()) return hidden def setHidden(self, name, skinname, hidden): skin = self._hidden.setdefault(skinname, PersistentDict()) skin[name] = tuple(hidden) def getDefault(self, name): try: return self._defaults.get(name) except AttributeError: # Backward compatibility self._defaults = PersistentDict() self.setDefault(name, 'Plone Default') return self.getDefault(name) def setDefault(self, name, skinname): try: self._defaults[name] = skinname except AttributeError: # Backward compatibility self._defaults = PersistentDict() self.setDefault(name, skinname)
class DavizSettings(SimpleItem): """ Daviz Settings """ meta_type = "EEA Daviz Settings" security = ClassSecurityInfo() implements(IDavizSettings) id = 'portal_daviz' manage_options = ( {'label': 'Edit', 'action': 'zmi_edit_html'}, ) + SimpleItem.manage_options def __init__(self, p_id, title="all daviz settings"): super(DavizSettings, self).__init__() self._setId(p_id) self.title = title self.settings = PersistentDict() site = getSite() sm = site.getSiteManager() ds = sm.queryUtility(IDavizSettings) if ds: sm.unregisterUtility(ds, IDavizSettings) sm.registerUtility(self, IDavizSettings) def disabled(self, view, content_type): """ Is view disabled for given content_type """ if not isinstance(view, (str, unicode)): view = getattr(view, '__name__', '') if not isinstance(content_type, (str, unicode)): content_type = getattr(content_type, 'portal_type', getattr(content_type, 'meta_type', None)) portal_types = self.settings.get(u'forbidden.%s' % view, None) or [] return content_type in portal_types
class Base(object): use_interface = None def __init__(self, context): self.context = context annotations = IAnnotations(self.context) self._metadata = annotations.get('wc.pageturner', None) if self._metadata is None: self._metadata = PersistentDict() self._metadata['last_updated'] = DateTime('1901/01/01').ISO8601() annotations['wc.pageturner'] = self._metadata def __setattr__(self, name, value): if name[0] == '_' or name in ['context', 'use_interface']: self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): default = None if name in self.use_interface.names(): default = self.use_interface[name].default return self._metadata.get(name, default)
class Base(object): use_interface = None def __init__(self, context): self.context = context annotations = IAnnotations(self.context) self._metadata = annotations.get('collective.documentviewer', None) if self._metadata is None: self._metadata = PersistentDict() self._metadata['last_updated'] = DateTime('1901/01/01').ISO8601() self.storage_version = STORAGE_VERSION annotations['collective.documentviewer'] = self._metadata def __setattr__(self, name, value): if name[0] == '_' or name in ['context', 'use_interface']: self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): default = None if name in self.use_interface.names(): default = self.use_interface[name].default elif name in _defaults: default = _defaults.get(name, None) return self._metadata.get(name, default)
class Base(object): use_interface = None def __init__(self, context): self.context = context annotations = IAnnotations(self.context) self._metadata = annotations.get("collective.documentviewer", None) if self._metadata is None: self._metadata = PersistentDict() self._metadata["last_updated"] = DateTime("1901/01/01").ISO8601() self.storage_version = STORAGE_VERSION annotations["collective.documentviewer"] = self._metadata def __setattr__(self, name, value): if name[0] == "_" or name in ["context", "use_interface"]: self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): default = None if name in self.use_interface.names(): default = self.use_interface[name].default elif name in _defaults: default = _defaults.get(name, None) return self._metadata.get(name, default)
class AnnotationAdapter(object): """Abstract Base Class for an annotation storage. If the annotation wasn't set, it won't be created until the first attempt to set a property on this adapter. So, the context doesn't get polluted with annotations by accident. """ ANNOTATION_KEY = None def __init__(self, context): self.context = context annotations = IAnnotations(context) self._data = annotations.get(self.ANNOTATION_KEY, None) def __setattr__(self, name, value): if name in ('context', '_data', 'ANNOTATION_KEY'): self.__dict__[name] = value else: if self._data is None: self._data = PersistentDict() annotations = IAnnotations(self.context) annotations[self.ANNOTATION_KEY] = self._data self._data[name] = value def __getattr__(self, name): return self._data.get(name, None) if self._data else None
class AnnotationAdapter(object): """Abstract Base Class for an annotation storage. If the annotation wasn't set, it won't be created until the first attempt to set a property on this adapter. So, the context doesn't get polluted with annotations by accident. """ ANNOTATION_KEY = None def __init__(self, context): self.context = context annotations = IAnnotations(context) self._data = annotations.get(self.ANNOTATION_KEY, None) def __setattr__(self, name, value): if name in ('context', '_data', 'ANNOTATION_KEY'): self.__dict__[name] = value else: if self._data is None: self._data = PersistentDict() annotations = IAnnotations(self.context) annotations[self.ANNOTATION_KEY] = self._data self._data[name] = value def __getattr__(self, name): return self._data and self._data.get(name, None) or None
class Base(object): use_interface = None def __init__(self, context): self.context = context annotations = IAnnotations(self.context) self._metadata = annotations.get('vindula.streaming', None) if self._metadata is None: self._metadata = PersistentDict() self._metadata['last_updated'] = DateTime('1901/01/01').ISO8601() self.storage_version = STORAGE_VERSION annotations['vindula.streaming'] = self._metadata def __setattr__(self, name, value): if name[0] == '_' or name in ['context', 'use_interface']: self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): default = None if name in self.use_interface.names(): default = self.use_interface[name].default elif name in _defaults: default = _defaults.get(name, None) return self._metadata.get(name, default)
class Base(object): use_interface = None def __init__(self, context): self.context = context annotations = IAnnotations(self.context) self._metadata = annotations.get('wildcard.media', None) def __setattr__(self, name, value): if name[0] == '_' or name in ['context', 'use_interface']: self.__dict__[name] = value else: if self._metadata is None: self._metadata = PersistentDict() annotations = IAnnotations(self.context) annotations['wildcard.media'] = self._metadata self._metadata[name] = value def __getattr__(self, name): default = None if name in self.use_interface.names(): default = self.use_interface[name].default if self._metadata is None: return default return self._metadata.get(name, default)
class FeedSettings(object): implements(IFeedSettings) adapts(ISyndicatable) def __init__(self, context): self.context = context annotations = IAnnotations(context) self._metadata = annotations.get(FEED_SETTINGS_KEY, None) if self._metadata is None: self._metadata = PersistentDict() annotations[FEED_SETTINGS_KEY] = self._metadata registry = getUtility(IRegistry) self.site_settings = registry.forInterface(ISiteSyndicationSettings) def __setattr__(self, name, value): if name in ('context', '_metadata', 'site_settings'): self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): default = None if name in ISiteSyndicationSettings.names(): default = getattr(self.site_settings, name) elif name == 'enabled' and self.site_settings.default_enabled: default = True elif name in IFeedSettings.names(): default = IFeedSettings[name].default return self._metadata.get(name, default)
class RosterSettings(object): use_interface = None def __init__(self, context, interface): self.use_interface = interface self.context = context annotations = IAnnotations(self.context) self._metadata = annotations.get('collective.eventmanager', None) if self._metadata is None: self._metadata = PersistentDict() annotations['collective.eventmanager'] = self._metadata def __setattr__(self, name, value): if name[0] == '_' or name in ['context', 'use_interface']: self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): default = None if name in self.use_interface.names(): default = self.use_interface[name].default return self._metadata.get(name, default)
def copy_meta(self): # XXX disable working copy support return json.dumps({ 'newId': self.request.get('metaId'), 'success': True, 'locked': False }) _id = self.request.get('metaId') copy_id = self.get_working_copy_meta_id() annotations = IAnnotations(self.context) data = annotations.get(TILE_ANNOTATIONS_KEY_PREFIX + '.' + _id) if not data: data = PersistentDict() if ('locked' in data and self.request.get( 'override', '').lower() not in ('y', 'yes', '1', 'true', 't') and api.user.get_current().getId() != data['locked']['user']): return json.dumps({ 'locked': True, 'success': False, 'lock_data': data['locked'] }) if TILE_ANNOTATIONS_KEY_PREFIX + '.' + copy_id in annotations: # cut out, we're good, resume existing return json.dumps({ 'newId': copy_id, 'success': True, 'locked': False }) version_key = self.get_working_copy_key() tile_mapping = {} new_tiles = [] for tile in data.get('tiles', []): # make copies of all the tiles tile_id = tile['id'] copy_tile_id = '{}-{}'.format(tile_id, version_key) tile_data = annotations.get(TILE_ANNOTATIONS_KEY_PREFIX + '.' + tile_id) if tile_data: annotations[TILE_ANNOTATIONS_KEY_PREFIX + '.' + copy_tile_id] = deepcopy(tile_data) new_tile_info = deepcopy(tile) new_tile_info['id'] = copy_tile_id new_tiles.append(new_tile_info) tile_mapping[tile_id] = copy_tile_id new_data = PersistentDict(dict(data)) new_data.update({'tiles': new_tiles, 'mapping': tile_mapping}) data.update({ 'locked': { 'when': DateTime().ISO8601(), 'user': api.user.get_current().getId() } }) annotations[TILE_ANNOTATIONS_KEY_PREFIX + '.' + copy_id] = new_data return json.dumps({'newId': copy_id, 'success': True, 'locked': False})
class TilesSettings(object): """ """ implements(IPageTilesSettings, IPageTilesSettings) interfaces = [] def __init__(self, context): self.context = context try: annotations = IAnnotations(self.context) except TypeError: # XXX for things like plone.app.event, traversers # are not adaptable so we need to look at the parent here self.context = aq_parent(context) annotations = IAnnotations(self.context) self._metadata = annotations.get('tx.tiles', None) if self._metadata is None: self._metadata = PersistentDict() annotations['tx.tiles'] = self._metadata ctx = aq_inner(context) rootctx = getToolByName(ctx, 'portal_url').getPortalObject() rootannotations = IAnnotations(rootctx) self._rootmetadata = rootannotations.get('tx.tiles', None) if self._rootmetadata is None: self._rootmetadata = PersistentDict() rootannotations['tx.tiles'] = self._rootmetadata @property def __parent__(self): return self.context @property def __roles__(self): return self.context.__roles__ def __setattr__(self, name, value): if name[0] == '_' or name in ['context', 'interfaces']: self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): value = self._metadata.get(name) if value is None: # first check to see if there are global settings if name in self._rootmetadata: return self._rootmetadata[name] else: # no global settings, check to see if there are defaults for interface in self.interfaces: v = interface.get(name) if v: return v.default return value
class UserIdentities(Persistent): def __init__(self, userid): self.userid = userid self._identities = PersistentDict() self._sheet = None self._secret = str(uuid.uuid4()) @property def secret(self): return self._secret def check_password(self, password): return password == self._secret def handle_result(self, result): """add a authomatic result to this user """ self._sheet = None # invalidate property sheet self._identities[result.provider.name] = UserIdentity(result) def identity(self, provider): """users identity at a distinct provider """ return self._identities.get(provider, None) def update_userdata(self, result): self._sheet = None # invalidate property sheet identity = self._identities[result.provider.name] identity.update(result.user.to_dict()) @property def propertysheet(self): if self._sheet is not None: return self._sheet # build sheet from identities pdata = dict(id=self.userid) cfgs_providers = authomatic_cfg() for provider_name in cfgs_providers: identity = self.identity(provider_name) if identity is None: continue logger.debug(identity) cfg = cfgs_providers[provider_name] for akey, pkey in cfg.get('propertymap', {}).items(): # Always search first on the user attributes, then on the raw # data this guaratees we do not break existing configurations ainfo = identity.get(akey, identity['data'].get(akey, None)) if ainfo is None: continue if isinstance(pkey, dict): for k, v in pkey.items(): pdata[k] = ainfo.get(v) else: pdata[pkey] = ainfo self._sheet = UserPropertySheet(**pdata) return self._sheet
class GallerySettings(object): """ Just uses Annotation storage to save and retrieve the data... """ implements(IGallerySettings) # these are settings for defaults that are not listed # in the interface because I don't want them to show up # in the schema defaults = { 'last_cooked_time_in_seconds': 0, 'cooked_images': [] } def __init__(self, context, interfaces=[IGallerySettings]): """ The interfaces argument allows you to customize which interface these settings implemenet. """ self.context = context self._interfaces = interfaces if type(self._interfaces) not in (list, tuple): self._interfaces = [self._interfaces] self._interfaces = list(self._interfaces) if IGallerySettings not in self._interfaces: self._interfaces.append(IGallerySettings) annotations = IAnnotations(context) self._metadata = annotations.get('collective.plonetruegallery', None) if self._metadata is None: self._metadata = PersistentDict() annotations['collective.plonetruegallery'] = self._metadata def __setattr__(self, name, value): if name in ('context', '_metadata', '_interfaces', 'defaults'): self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): """ since we have multiple settings that are possible to be used here, we have to interate over those interfaces to find the default values here. """ default = None if name in self.defaults: default = self.defaults[name] for iface in self._interfaces: if name in iface.names(): default = iface[name].default return self._metadata.get(name, default)
class SliderSettings(object): """ Pretty much copied how it is done in Slideshow Folder hopefully no one is foolish enough to want a custom slider and a view slider. If they are then the settings will overlap. """ implements(IPageSliderSettings) interfaces = [] def __init__(self, context): self.context = context annotations = IAnnotations(self.context) self._metadata = annotations.get('collective.easyslider', None) if self._metadata is None: self._metadata = PersistentDict() annotations['collective.easyslider'] = self._metadata ctx = aq_inner(context) rootctx = getToolByName(ctx, 'portal_url').getPortalObject() rootannotations = IAnnotations(rootctx) self._rootmetadata = rootannotations.get('collective.easyslider', None) if self._rootmetadata is None: self._rootmetadata = PersistentDict() rootannotations['collective.easyslider'] = self._rootmetadata @property def __parent__(self): return self.context @property def __roles__(self): return self.context.__roles__ def __setattr__(self, name, value): if name[0] == '_' or name in ['context', 'interfaces']: self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): value = self._metadata.get(name) if value is None: # first check to see if there are global settings if name in self._rootmetadata: return self._rootmetadata[name] else: # no global settings, check to see if there are defaults for interface in self.interfaces: v = interface.get(name) if v: return v.default return value
class CatalogBlacklist(UniqueObject, SimpleItem): implements(ICatalogBlacklist) id = 'portal_catalogblacklist' meta_type = 'Catalog Blacklist Tool' security = ClassSecurityInfo() def __init__(self, id=None): self._blacklisted_types = PersistentDict() self._blacklisted_interfaces = PersistentDict() security.declarePrivate('extend') def extend(self, blacklisted_types=None, blacklisted_interfaces=None): """ extend the blacklisted indexes for the given types or interfaces """ if blacklisted_types is not None: for pt, indexnames in blacklisted_types.items(): self._blacklisted_types.setdefault(pt, []) for name in indexnames: if name not in self._blacklisted_types[pt]: self._blacklisted_types[pt].append(name) self._blacklisted_types._p_changed = 1 if blacklisted_interfaces is not None: for iface, indexnames in blacklisted_interfaces.items(): if isinstance(iface, StringTypes): iface = resolve(iface) self._blacklisted_interfaces.setdefault(iface, []) for name in indexnames: if name not in self._blacklisted_interfaces[iface]: self._blacklisted_interfaces[iface].append(name) self._blacklisted_interfaces._p_changed = 1 security.declarePrivate('getBlackListedIndexesForObject') def getBlackListedIndexesForObject(self, object): """ return blacklisted indexes for object """ portal_type = getattr(object, 'portal_type', None) blacklisted = [] for indexname in self._blacklisted_types.get(portal_type, []): blacklisted.append(indexname) # Inspect the interfaces for iface, indexes in \ self._blacklisted_interfaces.items(): if iface.providedBy(object): for indexname in indexes: if indexname not in blacklisted: blacklisted.append(indexname) return blacklisted
def add_view(self, name, **kwargs): """ Add view >>> _ = visualization.add_view(name='daviz.map', ... lat='latitude', long='longitude') >>> view = visualization.view('daviz.map') >>> sorted(view.items()) [('lat', 'latitude'), ('long', 'longitude'), ('name', 'daviz.map')] """ config = self._views() kwargs.update({'name': name}) view = PersistentDict(kwargs) config.append(view) return view.get('name', '')
def add_facet(self, name, **kwargs): """ Add facet >>> _ = visualization.add_facet('country', a=1, b=2) >>> facet = visualization.facet('country') >>> sorted(facet.items()) [('a', 1), ('b', 2), ('label', 'country'), ('name', ...] """ config = self._facets() kwargs.update({'name': name}) kwargs.setdefault('type', u'daviz.list.facet') facet = PersistentDict(kwargs) config.append(facet) return facet.get('name', '')
class PortletAssignmentSettings(Contained): def __init__(self): self.data = PersistentDict() def __setitem__(self, name, value): self.data[name] = value def __delitem__(self, name): del self.data[name] def __getitem__(self, name): return self.data.__getitem__(name) def get(self, name, default=None): return self.data.get(name, default)
def add_source(self, name, **kwargs): """ Add source >>> _ = visualization.add_source('http://bit.ly/rdf', type='rdf') >>> source = visualization.source('http://bit.ly/rdf') >>> sorted(source.items()) [('name', 'http://bit.ly/rdf'), ('type', 'rdf')] """ config = self._sources() kwargs.update({'name': name}) kwargs.setdefault('type', u'json') source = PersistentDict(kwargs) config.append(source) return source.get('name', '')
class Tool(UniqueObject, SimpleItem): """ Contentrules subscription tool """ id = SUBSCRIPTION_TOOL meta_type = 'Contentrules Subscription Tool' plone_tool = 1 def __init__(self): self.subscriptions = PersistentDict() def registerUser(self, rule_id, email): """ Insert the given email address in the given rule_id """ if not rule_id in self.subscriptions: self.subscriptions[rule_id] = [email] else: if email in self.subscriptions[rule_id]: factory = getUtility(IVocabularyFactory, "contentrules.subscription.vocabularies.SubscriptionRulesVocabulary") vocabulary = factory(self) rule_term = vocabulary.getTerm(rule_id) msg = _('already_subscribed_error', default='The given email is already present for "${title}"', mapping=dict(title=rule_term.title)) return False, msg else: self.subscriptions[rule_id].append(email) return True, "" def getSubscriptions(self): """ Return the list of subscriptions """ return self.subscriptions def getActionUIDS(self): """ return a list of email addresses for the given rule_id """ return self.subscriptions.keys() def getRegisteredList(self, rule_id): """ return a list of email addresses for the given rule_id """ return self.subscriptions.get(rule_id, [])
class UserAnnotation(object): """Stores annotations.""" def __init__(self, principalId, store=None): self.principalId = principalId # _v_store is used to remember a mapping object that we should # be saved in if we ever change self._v_store = store self._data = PersistentDict() if store is None else store.get( principalId, PersistentDict()) def __bool__(self): return bool(self._data) __nonzero__ = __bool__ def __getitem__(self, key): return self._data[key] def get(self, key, default=None): return self._data.get(key, default) def keys(self): return self._data.keys() def __iter__(self): return iter(self._data) def __len__(self): return len(self._data) def __setitem__(self, key, value): if getattr(self, '_v_store', None) is not None: # _v_store is used to remember a mapping object that we should # be saved in if we ever change self._v_store[self.principalId] = self._data del self._v_store self._data[key] = value def __delitem__(self, key): del self._data[key] def __contains__(self, key): return key in self._data def items(self): return self._data.items()
class UserAnnotation(object): """Stores annotations.""" def __init__(self, principalId, store=None): self.principalId = principalId # _v_store is used to remember a mapping object that we should # be saved in if we ever change self._v_store = store self._data = PersistentDict() if store is None else store.get(principalId, PersistentDict()) def __bool__(self): return bool(self._data) __nonzero__ = __bool__ def __getitem__(self, key): return self._data[key] def get(self, key, default=None): return self._data.get(key, default) def keys(self): return self._data.keys() def __iter__(self): return iter(self._data) def __len__(self): return len(self._data) def __setitem__(self, key, value): if getattr(self, '_v_store', None) is not None: # _v_store is used to remember a mapping object that we should # be saved in if we ever change self._v_store[self.principalId] = self._data del self._v_store self._data[key] = value def __delitem__(self, key): del self._data[key] def __contains__(self, key): return key in self._data def items(self): return self._data.items()
class ExtendedMenuSettings(object): """ Pretty much copied how it is done in Slideshow Folder hopefully no one is foolish enough to want a custom slider and a view slider. If they are then the settings will overlap. """ implements(IExtendedMenuSettings) settings_key = "collective.qextendedmenu" def __init__(self, context, req=None): self.context = context annotations = IAnnotations(self.context) self._metadata = annotations.get(self.settings_key, None) if self._metadata is None: self._metadata = PersistentDict() annotations[self.settings_key] = self._metadata def __setattr__(self, name, value): if name[0] == "_" or name in ["context", "settings_key"]: self.__dict__[name] = value else: self._metadata[name] = value def getValue(self, name): value = getattr(self, name, None) if name == "html" and IRichTextValue.providedBy(value): if value.mimeType == value.outputMimeType: return self.raw_encoded else: transformer = ITransformer(self.context, None) if transformer is None: return None return transformer(value, value.outputMimeType) return value def __getattr__(self, name): value = self._metadata.get(name) if value is None: v = IExtendedMenuSettings.get(name) if v: return v.default return value
class FeedSettings(object): implements(IFeedSettings) adapts(ISyndicatable) def __init__(self, context): self.context = context self.annotations = IAnnotations(context) self.needs_saving = False self._metadata = self.annotations.get(FEED_SETTINGS_KEY, None) if self._metadata is None: self._metadata = PersistentDict() self.needs_saving = True registry = getUtility(IRegistry) self.site_settings = registry.forInterface(ISiteSyndicationSettings, check=False) def _set(self): """ what are we doing here you might ask? well, this causes us to write on read so only set on annotation if we need to """ if self.needs_saving: self.annotations[FEED_SETTINGS_KEY] = self._metadata def __setattr__(self, name, value): if name in ('context', '_metadata', 'site_settings', 'annotations', 'needs_saving'): self.__dict__[name] = value else: self._metadata[name] = value self._set() def __getattr__(self, name): default = None if name in ISiteSyndicationSettings.names(): default = getattr(self.site_settings, name) elif name == 'enabled' and self.site_settings.default_enabled: default = True elif name in IFeedSettings.names(): default = IFeedSettings[name].default return self._metadata.get(name, default)
def add_view(self, name, order=None, **kwargs): """ Add view >>> _ = visualization.add_view(name='daviz.map', ... lat='latitude', long='longitude') >>> view = visualization.view('daviz.map') >>> sorted(view.items()) [('lat', 'latitude'), ('long', 'longitude'), ('name', 'daviz.map')] """ config = self._views() kwargs.update({"name": name}) view = PersistentDict(kwargs) if isinstance(order, int): config.insert(order, view) else: config.append(view) return view.get("name", "")
def add_view(self, name, order=None, **kwargs): """ Add view >>> _ = visualization.add_view(name='daviz.map', ... lat='latitude', long='longitude') >>> view = visualization.view('daviz.map') >>> sorted(view.items()) [('lat', 'latitude'), ('long', 'longitude'), ('name', 'daviz.map')] """ config = self._views() kwargs.update({'name': name}) view = PersistentDict(kwargs) if isinstance(order, int): config.insert(order, view) else: config.append(view) return view.get('name', '')
class AnnotationStorage(object): def __init__(self, context): self.context = context try: annotations = IAnnotations(context) self._metadata = annotations.get(ANNOTATION_KEY, None) if self._metadata is None: self._metadata = PersistentDict() annotations[ANNOTATION_KEY] = self._metadata except TypeError: self._metadata = {} def put(self, name, value): self._metadata[name] = value def get(self, name, default=None): return self._metadata.get(name, default)
class FlowViewSettings(object): """ Just uses Annotation storage to save and retrieve the data... """ implements(IFlowViewSettings) defaults = {} def __init__(self, context, interfaces=[IFlowViewSettings]): self.context = context self._interfaces = interfaces if type(self._interfaces) not in (list, tuple): self._interfaces = [self._interfaces] self._interfaces = list(self._interfaces) if IFlowViewSettings not in self._interfaces: self._interfaces.append(IFlowViewSettings) annotations = IAnnotations(context) self._metadata = annotations.get('Solgema.FlowView', None) if self._metadata is None: self._metadata = PersistentDict() annotations['Solgema.FlowView'] = self._metadata def __setattr__(self, name, value): if name in ('context', '_metadata', '_interfaces', 'defaults'): self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): default = None if self.defaults.has_key(name): default = self.defaults[name] for iface in self._interfaces: if name in iface.names(): default = iface[name].default return self._metadata.get(name, default)
class MarscatsSettingsStorage(Persistent): implements(IMarscatsSettingsStorage) def __init__(self): self._fields = PersistentDict() def setStartupDir(self, fieldname, startup_dir, portal_type=None): field = self._fields.setdefault(fieldname, PersistentDict()) if portal_type is not None: portal_types = field.setdefault('portal_types', PersistentDict()) portal_types[portal_type] = startup_dir else: self._fields[fieldname]['startup_directory'] = startup_dir def getStartupDir(self, fieldname, portal_type=None, fallback=True, ispath=False): sd = '' if fallback: sd = CAT_CONTAINER if fieldname in self._fields.keys(): field = self._fields.get(fieldname) sd = field.get('startup_directory', sd) if portal_type is not None: pts = field.get('portal_types') if pts is not None: sd = pts.get(portal_type, sd) if ispath: if not sd.startswith(CAT_CONTAINER): sd = CAT_CONTAINER + '/' + sd # sd = '/' + sd return sd def getFieldNames(self): return list(self._fields) def getTypesForField(self, fieldname): if fieldname in self._fields: field = self._fields[fieldname] if 'portal_types' in field and len(field['portal_types']): return list(field['portal_types']) return list()
class AnnotationAdapter(object): """Abstract Base Class for an annotation storage. """ ANNOTATION_KEY = None def __init__(self, context): self.context = context annotations = IAnnotations(context) self._data = annotations.get(self.ANNOTATION_KEY, None) if self._data is None: self._data = PersistentDict() annotations[self.ANNOTATION_KEY] = self._data def __setattr__(self, name, value): if name in ('context', '_data'): self.__dict__[name] = value else: self._data[name] = value def __getattr__(self, name): return self._data.get(name, None)
class ContextKeys(Persistent): grok.implements(IContextKeys) def __init__(self): self._items = PersistentDict() def link(self, key, context): id = hash(IKeyReference(context)) ids = self._items.setdefault(key, PersistentSet()) ids.add(id) def unlink(self, key, context): id = hash(IKeyReference(context)) ids = self._items.setdefault(key, PersistentSet()) ids.discard(id) if not ids: del self._items[key] def unlinkKey(self, key): if key in self._items: del self._items[key] def unlinkContext(self, context): id = hash(IKeyReference(context)) keys_removed = set() for key, ids in self._items.items(): ids.discard(id) if not ids: keys_removed.add(key) for key in keys_removed: del self._items[key] return keys_removed def isLinked(self, key, context): id = hash(IKeyReference(context)) return id in self._items.get(key, set()) def __contains__(self, key): return key in self._items
class Annotations(Persistent, Location): """Stores annotations.""" interface.implements(IAnnotations) def __init__(self, principalId, store=None): self.principalId = principalId self.data = PersistentDict() # We don't really expect that many # _v_store is used to remember a mapping object that we should # be saved in if we ever change self._v_store = store def __getitem__(self, key): try: return self.data[key] except KeyError: # We failed locally: delegate to a higher-level utility. utility = queryNextUtility(self, IPrincipalAnnotationUtility) if utility is not None: annotations = utility.getAnnotationsById(self.principalId) return annotations[key] raise def __setitem__(self, key, value): if getattr(self, '_v_store', None) is not None: # _v_store is used to remember a mapping object that we should # be saved in if we ever change self._v_store[self.principalId] = self del self._v_store self.data[key] = value def __delitem__(self, key): del self.data[key] def get(self, key, default=None): return self.data.get(key, default)
class EasysliderviewletSettings(object): """ Copied from Nathan, let's see if it works. """ implements(IEasysliderviewletSettings) interfaces = [] def __init__(self, context): self.context = context annotations = IAnnotations(self.context) self._metadata = annotations.get('medialog.easysliderviewlet', None) if self._metadata is None: self._metadata = PersistentDict() annotations['medialog.easysliderviewlet'] = self._metadata @property def __parent__(self): return self.context @property def __roles__(self): return self.context.__roles__ def __setattr__(self, name, value): if name[0] == '_' or name in ['context', 'interfaces']: self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): value = self._metadata.get(name) if value is None: v = IEasysliderviewletSettings.get(name) if v: return v.default return value
class AccessControlCustomisations(Persistent): implements(IAccessControlCustomisations) def __init__(self): self._settings = PersistentDict() def getSetting(self, key): for setting in self: if setting.key == key: return setting else: raise KeyError("there is no AccessControlSetting" " associated with this key.") def get(self, key): return self._settings.get(key, self.getSetting(key).default) def set(self, key, value): if self.getSetting(key): self._settings[key] = value def __iter__(self): settings = subscribers([None], IAccessControlSetting) return iter(settings)
class MockContainer(PortalContent): """ """ implements(IUIDKeyedContainer, IAttributeUUID) def __init__(self, id, items=None): super(MockContainer, self).__init__() self.id = id self._items = PersistentDict(items) def get(self, uid, default=None): v = self._items.get(str(uid), None) if v and getattr(v, '_v_parent', None) is None: v._v_parent = self # container marks obtained item with context return v # just here for test use: def register(self, uid, item): self._items[uid] = item def unregister(self, uid): del (self._items[uid]) def __contains__(self, uid): return uid in self._items # here for indexing purposes, even though these indexes may # be handled differently in real life (e.g. indexer adapter): def UID(self): return IUUID(self) def contains(self): return self._items.keys() # UUIDs of contained items def items(self): return self._items.items()
class MockContainer(PortalContent): """ """ implements(IUIDKeyedContainer, IAttributeUUID) def __init__(self, id, items=None): super(MockContainer, self).__init__() self.id = id self._items = PersistentDict(items) def get(self, uid, default=None): v = self._items.get(str(uid), None) if v and getattr(v, '_v_parent', None) is None: v._v_parent = self # container marks obtained item with context return v # just here for test use: def register(self, uid, item): self._items[uid] = item def unregister(self, uid): del(self._items[uid]) def __contains__(self, uid): return uid in self._items # here for indexing purposes, even though these indexes may # be handled differently in real life (e.g. indexer adapter): def UID(self): return IUUID(self) def contains(self): return self._items.keys() # UUIDs of contained items def items(self): return self._items.items()
class RoleProtectedObject(Persistent, Contained): """Base class for object protected by roles""" inherit_parent_security = FieldProperty( IRoleProtectedObject['inherit_parent_security']) everyone_denied = FieldProperty(IRoleProtectedObject['everyone_denied']) everyone_granted = FieldProperty(IRoleProtectedObject['everyone_granted']) authenticated_denied = FieldProperty( IRoleProtectedObject['authenticated_denied']) authenticated_granted = FieldProperty( IRoleProtectedObject['authenticated_granted']) inherit_parent_roles = FieldProperty( IRoleProtectedObject['inherit_parent_roles']) def __init__(self): self._principals_by_role = PersistentDict() self._roles_by_principal = PersistentDict() def get_everyone_denied(self): """Get permissions denied to everyone""" permissions = self.everyone_denied or set() if self.inherit_parent_security: for parent in lineage(self): if parent in (self, self.__parent__): continue protection = IProtectedObject(parent, None) if protection is not None: permissions = permissions | (protection.everyone_denied or set()) return permissions def get_everyone_granted(self): """Get permissions granted to everyone""" permissions = self.everyone_granted or set() if self.inherit_parent_security: for parent in lineage(self): if parent in (self, self.__parent__): continue protection = IProtectedObject(parent, None) if protection is not None: permissions = permissions | (protection.everyone_granted or set()) return permissions def get_authenticated_denied(self): """Get permissions denied to authenticated users""" permissions = self.authenticated_denied or set() if self.inherit_parent_security: for parent in lineage(self): if parent in (self, self.__parent__): continue protection = IProtectedObject(parent, None) if protection is not None: permissions = permissions | ( protection.authenticated_denied or set()) return permissions def get_authenticated_granted(self): """Get permissions granted to authenticated users""" permissions = self.authenticated_granted or set() if self.inherit_parent_security: for parent in lineage(self): if parent in (self, self.__parent__): continue protection = IProtectedObject(parent, None) if protection is not None: permissions = permissions | ( protection.authenticated_granted or set()) return permissions def grant_role(self, role_id, principal_ids): """Grant role to selected principals""" registry = get_pyramid_registry() if IRole.providedBy(role_id): role_id = role_id.id if isinstance(principal_ids, str): principal_ids = {principal_ids} role_principals = self._principals_by_role.get(role_id) or set() for principal_id in principal_ids: if IPrincipalInfo.providedBy(principal_id): principal_id = principal_id.id if principal_id not in role_principals: principal_roles = self._roles_by_principal.get( principal_id) or set() role_principals.add(principal_id) principal_roles.add(role_id) self._roles_by_principal[principal_id] = principal_roles self._principals_by_role[role_id] = role_principals registry.notify(GrantedRoleEvent(self, role_id, principal_id)) def revoke_role(self, role_id, principal_ids): """Revoke role to selected principals""" registry = get_pyramid_registry() if IRole.providedBy(role_id): role_id = role_id.id if isinstance(principal_ids, str): principal_ids = {principal_ids} role_principals = self._principals_by_role.get(role_id) or set() for principal_id in principal_ids.copy(): if IPrincipalInfo.providedBy(principal_id): principal_id = principal_id.id if principal_id in role_principals: principal_roles = self._roles_by_principal.get( principal_id) or set() if principal_id in role_principals: role_principals.remove(principal_id) if role_id in principal_roles: principal_roles.remove(role_id) if principal_roles: self._roles_by_principal[principal_id] = principal_roles elif principal_id in self._roles_by_principal: del self._roles_by_principal[principal_id] if role_principals: self._principals_by_role[role_id] = role_principals elif role_id in self._principals_by_role: del self._principals_by_role[role_id] registry.notify(RevokedRoleEvent(self, role_id, principal_id)) def get_principals(self, role_id): """Get principals which have selected role granted""" if IRole.providedBy(role_id): role_id = role_id.id return self._principals_by_role.get(role_id) or set() def get_roles(self, principal_id): """Get roles for given principal""" if IPrincipalInfo.providedBy(principal_id): principal_id = principal_id.id return self._roles_by_principal.get(principal_id) or set() def get_permissions(self, principal_id): """Get permissions for given principal""" registry = get_pyramid_registry() result = set() for role_id in self.get_roles(principal_id): role = registry.queryUtility(IRole, role_id) result |= role.permissions or set() return result def get_granted_roles(self): """Get granted roles on current context or parents""" roles = set(self._principals_by_role.keys()) if self.inherit_parent_roles: for parent in lineage(self): if parent in (self, self.__parent__): continue protection = IProtectedObject(parent, None) if protection is not None: roles = roles | protection.get_granted_roles() return roles @request_property(key=None) def __acl__(self): """Get ACL for current context The result is stored into current request annotations, so it's not supposed to change during request lifetime. """ # always grant all permissions to system manager # and 'public' permission to everyone result = [(Allow, ADMIN_USER_ID, ALL_PERMISSIONS), (Allow, Everyone, {PUBLIC_PERMISSION})] # grant access to all roles permissions for role_id in self.get_granted_roles(): role = query_utility(IRole, role_id) if role is not None: result.append( (Allow, ROLE_ID.format(role_id), role.permissions)) # add denied permissions to everyone and authenticated permissions = self.get_everyone_denied() if permissions: result.append((Deny, Everyone, permissions)) permissions = self.get_authenticated_denied() if permissions: result.append((Deny, Authenticated, permissions)) # add allowed permissions to everyone and authenticated permissions = self.get_authenticated_granted() if permissions: result.append((Allow, Authenticated, permissions)) permissions = self.get_everyone_granted() if permissions: result.append((Allow, Everyone, permissions)) # deny all parent permissions if inheritance is disabled if not self.inherit_parent_security: result.append(DENY_ALL) LOGGER.debug('ACL({0!r}) = {1}'.format(self.__parent__, str(result))) return result
class SliderSettings(object): """ Pretty much copied how it is done in Slideshow Folder hopefully no one is foolish enough to want a custom slider and a view slider. If they are then the settings will overlap. """ implements(IPageSliderSettings) interfaces = [] def __init__(self, context): self.context = context try: annotations = IAnnotations(self.context) except TypeError: # XXX for things like plone.app.event, traversers # are not adaptable so we need to look at the parent here self.context = aq_parent(context) annotations = IAnnotations(self.context) self._metadata = annotations.get('collective.easyslider', None) if self._metadata is None: self._metadata = PersistentDict() annotations['collective.easyslider'] = self._metadata ctx = aq_inner(context) rootctx = getToolByName(ctx, 'portal_url').getPortalObject() rootannotations = IAnnotations(rootctx) self._rootmetadata = rootannotations.get('collective.easyslider', None) if self._rootmetadata is None: self._rootmetadata = PersistentDict() rootannotations['collective.easyslider'] = self._rootmetadata @property def __parent__(self): return self.context @property def __roles__(self): return self.context.__roles__ def __setattr__(self, name, value): if name[0] == '_' or name in ['context', 'interfaces']: self.__dict__[name] = value else: self._metadata[name] = value def __getattr__(self, name): value = self._metadata.get(name) if value is None: # first check to see if there are global settings if name in self._rootmetadata: return self._rootmetadata[name] else: # no global settings, check to see if there are defaults for interface in self.interfaces: v = interface.get(name) if v: return v.default return value
class Person(User, SearchableEntity, CorrelableEntity, Debatable): """Person class""" type_title = _('Person') icon = 'icon glyphicon glyphicon-user' #'icon novaideo-icon icon-user' templates = { 'default': 'novaideo:views/templates/person_result.pt', 'bloc': 'novaideo:views/templates/person_bloc.pt', 'small': 'novaideo:views/templates/small_person_result.pt', 'popover': 'novaideo:views/templates/person_popover.pt', 'card': 'novaideo:views/templates/person_card.pt', 'header': 'novaideo:views/templates/person_header.pt', } default_picture = 'novaideo:static/images/user100.png' name = renamer() tokens = CompositeMultipleProperty('tokens') tokens_ref = SharedMultipleProperty('tokens_ref') organization = SharedUniqueProperty('organization', 'members') events = SharedMultipleProperty('events', 'author') picture = CompositeUniqueProperty('picture') cover_picture = CompositeUniqueProperty('cover_picture') ideas = SharedMultipleProperty('ideas', 'author') selections = SharedMultipleProperty('selections') working_groups = SharedMultipleProperty('working_groups', 'members') wg_participations = SharedMultipleProperty('wg_participations', 'wating_list_participation') old_alerts = SharedMultipleProperty('old_alerts') following_channels = SharedMultipleProperty('following_channels', 'members') folders = SharedMultipleProperty('folders', 'author') questions = SharedMultipleProperty('questions', 'author') challenges = SharedMultipleProperty('challenges', 'author') ballots = CompositeMultipleProperty('ballots') mask = SharedUniqueProperty('mask', 'member') def __init__(self, **kwargs): self.branches = PersistentList() self.keywords = PersistentList() super(Person, self).__init__(**kwargs) kwargs.pop('password', None) self.set_data(kwargs) self.set_title() self.last_connection = datetime.datetime.now(tz=pytz.UTC) self._read_at = OOBTree() self.guide_tour_data = PersistentDict({}) self.confidence_index = 0 self._notes = OOBTree() self.allocated_tokens = OOBTree() self.len_allocated_tokens = PersistentDict({}) self.reserved_tokens = PersistentList([]) self._submited_at = OOBTree() self._reported_at = OOBTree() def __setattr__(self, name, value): super(Person, self).__setattr__(name, value) if name == 'organization' and value: self.init_contents_organizations() def get_len_tokens(self, root=None, exclude_reserved_tokens=False): root = root or getSite() return root.tokens_mini if exclude_reserved_tokens \ else root.tokens_mini + len(self.reserved_tokens) def get_len_evaluations(self, exclude_reserved_tokens=False): total = self.len_allocated_tokens.get(Evaluations.support, 0) + \ self.len_allocated_tokens.get(Evaluations.oppose, 0) if exclude_reserved_tokens: return total - len([ o for o in self.reserved_tokens if o in self.allocated_tokens ]) return total def get_len_free_tokens(self, root=None, exclude_reserved_tokens=False): root = root or getSite() return self.get_len_tokens(root, exclude_reserved_tokens) - \ self.get_len_evaluations(exclude_reserved_tokens) def has_token(self, obj=None, root=None): root = root or getSite() obj_oid = get_oid(obj, None) if obj_oid and obj_oid in self.reserved_tokens: return obj_oid not in self.allocated_tokens return self.get_len_free_tokens(root, True) > 0 def add_token(self, obj, evaluation_type, root=None): if self.has_token(obj, root): self.allocated_tokens[get_oid(obj)] = evaluation_type self.len_allocated_tokens.setdefault(evaluation_type, 0) self.len_allocated_tokens[evaluation_type] += 1 def remove_token(self, obj): obj_oid = get_oid(obj) if obj_oid in self.allocated_tokens: evaluation_type = self.allocated_tokens.pop(obj_oid) self.len_allocated_tokens.setdefault(evaluation_type, 0) self.len_allocated_tokens[evaluation_type] -= 1 def add_reserved_token(self, obj): obj_oid = get_oid(obj) if obj_oid not in self.reserved_tokens: self.reserved_tokens.append(obj_oid) def remove_reserved_token(self, obj): obj_oid = get_oid(obj) if obj_oid in self.reserved_tokens: self.reserved_tokens.remove(obj_oid) def evaluated_objs(self, evaluation_type=None): if evaluation_type: return [ get_obj(key) for value, key in self.allocated_tokens.byValue( evaluation_type) ] return [get_obj(key) for key in self.allocated_tokens.keys()] def evaluated_objs_ids(self, evaluation_type=None): if evaluation_type: return [ key for value, key in self.allocated_tokens.byValue( evaluation_type) ] return list(self.allocated_tokens.keys()) def init_contents_organizations(self): novaideo_catalog = find_catalog('novaideo') dace_catalog = find_catalog('dace') organizations_index = novaideo_catalog['organizations'] object_authors_index = novaideo_catalog['object_authors'] object_provides_index = dace_catalog['object_provides'] query = object_authors_index.any([get_oid(self)]) & \ object_provides_index.any( [Iidea.__identifier__, IProposal.__identifier__]) & \ organizations_index.any([0]) for entity in query.execute().all(): entity.init_organization() entity.reindex() def set_read_date(self, channel, date): self._read_at[get_oid(channel)] = date def get_read_date(self, channel): return self._read_at.get(get_oid(channel), datetime.datetime.now(tz=pytz.UTC)) def get_channel(self, user): all_channels = list(self.channels) all_channels.extend(list(getattr(user, 'channels', []))) for channel in all_channels: if user in channel.members and self in channel.members: return channel return None def addtoproperty(self, name, value, moving=None): super(Person, self).addtoproperty(name, value, moving) if name == 'selections': value.len_selections = getattr(value, 'len_selections', 0) value.len_selections += 1 def delfromproperty(self, name, value, moving=None): super(Person, self).delfromproperty(name, value, moving) if name == 'selections': value.len_selections = getattr(value, 'len_selections', 0) if value.len_selections > 0: value.len_selections -= 1 def set_title(self): if getattr(self, 'pseudonym', ''): self.title = self.pseudonym else: self.title = getattr(self, 'first_name', '') + ' ' + \ getattr(self, 'last_name', '') def add_note(self, user, context, note, date, time_constant): self._notes[date] = (get_oid(user), get_oid(context), note) self.calculate_confidence_index(time_constant) def get_questions(self, user): if user is self: return self.questions + getattr(self.mask, 'questions', []) return self.questions def get_ideas(self, user): if user is self: return self.ideas + getattr(self.mask, 'ideas', []) return self.ideas def get_working_groups(self, user): if user is self: return self.working_groups + getattr(self.mask, 'working_groups', []) return self.working_groups @property def proposals(self): return [wg.proposal for wg in self.working_groups] def get_proposals(self, user): if user is self: return self.proposals + getattr(self.mask, 'proposals', []) return self.proposals @property def contacts(self): return [s for s in self.selections if isinstance(s, Person)] @property def participations(self): result = [ p for p in list(self.proposals) if any(s in p.state for s in [ 'amendable', 'open to a working group', 'votes for publishing', 'votes for amendments' ]) ] return result def get_participations(self, user): if user is self: return self.participations + getattr(self.mask, 'participations', []) return self.participations @property def contents(self): result = [i for i in list(self.ideas) if i is i.current_version] result.extend(self.proposals) result.extend(self.questions) result.extend(self.challenges) result.extend(self.events) return result def get_contents(self, user): if user is self: return self.contents + getattr(self.mask, 'contents', []) return self.contents @property def active_working_groups(self): return [p.working_group for p in self.participations] def get_active_working_groups(self, user): if user is self: return self.active_working_groups + getattr( self.mask, 'active_working_groups', []) return self.active_working_groups def get_wg_participations(self, user): if user is self: return self.wg_participations + getattr(self.mask, 'wg_participations', []) return self.wg_participations @property def is_published(self): return 'active' in self.state @property def managed_organization(self): return get_objects_with_role(user=self, role='OrganizationResponsible') def get_confidence_index(self): return getattr(self, 'confidence_index', 0) def reindex(self): super(Person, self).reindex() root = getSite() self.__access_keys__ = PersistentList(generate_access_keys(self, root)) def get_picture_url(self, kind, default): if self.picture: img = getattr(self.picture, kind, None) if img: return img.url return default def get_more_contents_criteria(self): "return specific query, filter values" return None, None def set_organization(self, organization): current_organization = self.organization if organization: if current_organization is not organization: is_manager = current_organization and has_role( ('OrganizationResponsible', current_organization), self, ignore_superiors=True) if current_organization and is_manager: revoke_roles( self, (('OrganizationResponsible', current_organization), )) self.setproperty('organization', organization) elif current_organization: is_manager = has_role( ('OrganizationResponsible', current_organization), self, ignore_superiors=True) if is_manager: revoke_roles( self, (('OrganizationResponsible', current_organization), )) self.delfromproperty('organization', current_organization) @property def all_alerts(self): novaideo_catalog = find_catalog('novaideo') dace_catalog = find_catalog('dace') alert_keys_index = novaideo_catalog['alert_keys'] alert_exclude_keys_index = novaideo_catalog['alert_exclude_keys'] object_provides_index = dace_catalog['object_provides'] exclude = [str(get_oid(self))] if self.mask: exclude.append(str(get_oid(self.mask))) query = object_provides_index.any([IAlert.__identifier__]) & \ alert_keys_index.any(self.get_alerts_keys()) & \ alert_exclude_keys_index.notany(exclude) return query.execute() @property def alerts(self): old_alerts = [get_oid(a) for a in self.old_alerts] result = self.all_alerts def exclude(result_set, docids): filtered_ids = list(result_set.ids) for _id in docids: if _id in docids and _id in filtered_ids: filtered_ids.remove(_id) return result_set.__class__(filtered_ids, len(filtered_ids), result_set.resolver) return exclude(result, old_alerts) def get_alerts_keys(self): result = ['all', str(get_oid(self))] if self.mask: result.append(str(get_oid(self.mask))) return result def get_alerts(self, alerts=None, kind=None, subject=None, **kwargs): if alerts is None: alerts = self.alerts if kind: alerts = [a for a in alerts if a.is_kind_of(kind)] if subject: alerts = [a for a in alerts if subject in a.subjects] if kwargs: alerts = [a for a in alerts if a.has_args(**kwargs)] return alerts def calculate_confidence_index(self, time_constant): now = datetime.datetime.utcnow().timestamp() notes = np.array([v[2] for v in self._notes.values()]) dates = np.array([int(t.timestamp()) for t in self._notes.keys()]) time_c = time_constant * 86400 confidence_index = np.sum( np.dot(notes, np.exp(-np.log(2) * (now - dates) / time_c))) self.confidence_index = round(confidence_index, 1) @property def user_groups(self): groups = list(self.groups) if self.organization: groups.append(self.organization) if self.mask: groups.append(self.mask) return groups @property def user_locale(self): locale = getattr(self, 'locale', None) if not locale: locale = getSite(self).locale return locale def _init_mask(self, root): if not self.mask: mask = Mask() root.addtoproperty('masks', mask) self.setproperty('mask', mask) def get_mask(self, root=None): root = root if root else getSite() if not getattr(root, 'anonymisation', False): return self self._init_mask(root) return self.mask def add_submission(self, obj): now = datetime.datetime.now(tz=pytz.UTC) self._submited_at[now] = get_oid(obj) def add_report(self, obj): now = datetime.datetime.now(tz=pytz.UTC) self._reported_at[now] = get_oid(obj) def can_submit_idea(self, root=None): root = root if root else getSite() now = datetime.datetime.now(tz=pytz.UTC) monday = datetime.datetime.combine((now - datetime.timedelta(days=7)), datetime.time(0, 0, 0, tzinfo=pytz.UTC)) return len(self._submited_at.values(min=monday, max=now)) < getattr( root, 'nb_submission_maxi', 3) def can_report(self, root=None): root = root if root else getSite() now = datetime.datetime.now(tz=pytz.UTC) monday = datetime.datetime.combine((now - datetime.timedelta(days=7)), datetime.time(0, 0, 0, tzinfo=pytz.UTC)) return len(self._reported_at.values(min=monday, max=now)) < getattr( root, 'nb_reports_maxi', 3)
class OrderedContainer(Persistent, Contained): """ `OrderedContainer` maintains entries' order as added and moved. >>> oc = OrderedContainer() >>> int(IOrderedContainer.providedBy(oc)) 1 >>> len(oc) 0 """ implements(IOrderedContainer) def __init__(self): self._data = PersistentDict() self._order = PersistentList() def keys(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc.keys() ['foo'] >>> oc['baz'] = 'quux' >>> oc.keys() ['foo', 'baz'] >>> int(len(oc._order) == len(oc._data)) 1 """ return self._order[:] def __iter__(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc['baz'] = 'quux' >>> [i for i in oc] ['foo', 'baz'] >>> int(len(oc._order) == len(oc._data)) 1 """ return iter(self.keys()) def __getitem__(self, key): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> oc['foo'] 'bar' """ return self._data[key] def get(self, key, default=None): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> oc.get('foo') 'bar' >>> oc.get('funky', 'No chance, dude.') 'No chance, dude.' """ return self._data.get(key, default) def values(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc.values() ['bar'] >>> oc['baz'] = 'quux' >>> oc.values() ['bar', 'quux'] >>> int(len(oc._order) == len(oc._data)) 1 """ return [self._data[i] for i in self._order] def __len__(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> int(len(oc) == 0) 1 >>> oc['foo'] = 'bar' >>> int(len(oc) == 1) 1 """ return len(self._data) def items(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc.items() [('foo', 'bar')] >>> oc['baz'] = 'quux' >>> oc.items() [('foo', 'bar'), ('baz', 'quux')] >>> int(len(oc._order) == len(oc._data)) 1 """ return [(i, self._data[i]) for i in self._order] def __contains__(self, key): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> int('foo' in oc) 1 >>> int('quux' in oc) 0 """ return self._data.has_key(key) has_key = __contains__ def __setitem__(self, key, object): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc._order ['foo'] >>> oc['baz'] = 'quux' >>> oc._order ['foo', 'baz'] >>> int(len(oc._order) == len(oc._data)) 1 >>> oc['foo'] = 'baz' Traceback (most recent call last): ... KeyError: u'foo' >>> oc._order ['foo', 'baz'] """ existed = self._data.has_key(key) bad = False if isinstance(key, StringTypes): try: unicode(key) except UnicodeError: bad = True else: bad = True if bad: raise TypeError("'%s' is invalid, the key must be an " "ascii or unicode string" % key) if len(key) == 0: raise ValueError("The key cannot be an empty string") # We have to first update the order, so that the item is available, # otherwise most API functions will lie about their available values # when an event subscriber tries to do something with the container. if not existed: self._order.append(key) # This function creates a lot of events that other code listens to. try: setitem(self, self._data.__setitem__, key, object) except Exception, e: if not existed: self._order.remove(key) raise e return key
class NotificationTool(Folder): """ """ meta_type = core_constants.METATYPE_NOTIFICATIONTOOL icon = 'misc_/NaayaCore/NotificationTool.gif' meta_types = () all_meta_types = meta_types security = ClassSecurityInfo() # default configuration settings default_config = { 'admin_on_error': True, 'admin_on_edit': True, 'enable_instant': True, 'enable_daily': True, 'enable_anonymous': False, # Enable anonymous notifications 'daily_hour': 0, 'enable_weekly': True, 'weekly_day': 1, # 1 = monday, 7 = sunday 'weekly_hour': 0, 'enable_monthly': True, 'monthly_day': 1, # 1 = first day of the month 'monthly_hour': 0, 'notif_content_types': [], } def __init__(self, id, title): """ """ self.id = id self.title = title self.config = PersistentDict(self.default_config) self.timestamps = PersistentDict() # Confirmations list self.pending_anonymous_subscriptions = PersistentList() def get_config(self, key): return self.config.get(key) def get_location_link(self, location): if location: return self.restrictedTraverse(location, self.getSite()).absolute_url() else: return self.getSite().absolute_url() def _validate_subscription(self, **kw): """ Validate add/edit subscription for authorized and anonymous users """ if (kw['notif_type'] not in self.available_notif_types(kw['location']) and not (kw['notif_type'] == 'administrative' and self.checkPermissionPublishObjects())): raise i18n_exception(ValueError, 'Subscribing to ${notif_type} ' 'notifications in "${location}" not allowed', location=kw['location'] or self.getSite().title, notif_type=kw['notif_type']) try: obj = self.getSite().restrictedTraverse(kw['location']) except: raise i18n_exception(ValueError, 'This path is invalid or protected') try: subscription_container = ISubscriptionContainer(obj) except: raise i18n_exception(ValueError, 'Cannot subscribe to this folder') if kw.get('anonymous', False): # Check if subscription exists for this anonymous subscriber if not is_valid_email(kw.get('email', '')): raise i18n_exception( ValueError, 'Your e-mail address does not appear ' 'to be valid.') for id, subscription in subscription_container.list_with_keys(): # Normal subscriptions don't have e-mail if isinstance(subscription, AnonymousSubscription): if (subscription.email == kw['email'] and subscription.notif_type == kw['notif_type'] and subscription.lang == kw['lang']): raise i18n_exception(ValueError, 'Subscription already exists') def _sitemap_dict(self, form): """ Compose a sitemap dict """ node = form.get('node', '') if not node or node == '/': node = '' def traverse(objects, level=0, stop_level=2, exclude_root=False): """ Create a dict with node properties and children. This is a fixed level recursion. On some sites there are a lot of objects so we don't need to get the whole tree. """ res = [] for ob in objects: if ISubscriptionTarget.providedBy(ob) is False: continue children_objects = [] if level != stop_level: # Stop if the level is reached # Create a list of object's children if hasattr(ob, 'objectValues'): # Get only naaya container objects for child in ob.objectValues( self.get_naaya_containers_metatypes()): # Skip unsubmited/unapproved if not getattr(child, 'approved', False): continue elif not getattr(child, 'submitted', False): continue else: children_objects.append(child) if hasattr(ob, 'approved'): icon = ob.approved and ob.icon or ob.icon_marked else: icon = ob.icon children = traverse(children_objects, level + 1, stop_level) if exclude_root: # Return only the children if this is set return children res.append({ 'data': { 'title': self.utStrEscapeHTMLTags( self.utToUtf8(ob.title_or_id())), 'icon': icon }, 'attributes': { 'title': path_in_site(ob) }, 'children': children }) return res if node == '': tree_dict = traverse([self.getSite()]) else: tree_dict = traverse([self.restrictedTraverse(node)], exclude_root=True) return tree_dict security.declarePublic('sitemap') def sitemap(self, REQUEST=None, **kw): """ Return a json (for Ajax tree) representation of published objects marked with `ISubscriptionTarget` including the portal organized in a tree (sitemap) """ form = {} if REQUEST is not None: form = REQUEST.form REQUEST.RESPONSE.setHeader('content-type', 'application/json') else: form.update(kw) return json.dumps(self._sitemap_dict(form)) security.declarePrivate('add_account_subscription') def add_account_subscription(self, user_id, location, notif_type, lang, content_types=[]): """ Subscribe the user `user_id` """ self._validate_subscription(user_id=user_id, location=location, notif_type=notif_type, lang=lang, content_types=content_types) try: self.remove_account_subscription(user_id, location, notif_type, lang) except ValueError: pass obj = self.getSite().restrictedTraverse(location) subscription_container = ISubscriptionContainer(obj) subscription = AccountSubscription(user_id, notif_type, lang, content_types) subscription_container.add(subscription) security.declarePrivate('add_anonymous_subscription') def add_anonymous_subscription(self, **kw): """ Handle anonymous users """ self._validate_subscription(anonymous=True, **kw) subscription = AnonymousSubscription(**kw) # Add to temporary container self.pending_anonymous_subscriptions.append(subscription) # Send email email_tool = self.getSite().getEmailTool() email_from = email_tool.get_addr_from() email_template = EmailPageTemplateFile('emailpt/confirm.zpt', globals()) email_data = email_template.render_email(**{ 'key': subscription.key, 'here': self }) email_to = subscription.email email_tool.sendEmail(email_data['body_text'], email_to, email_from, email_data['subject']) security.declarePrivate('remove_account_subscription') def remove_account_subscription(self, user_id, location, notif_type, lang, content_types=None): obj = self.getSite().restrictedTraverse(location) subscription_container = ISubscriptionContainer(obj) n = utils.match_account_subscription(subscription_container, user_id, notif_type, lang, content_types) if n is None: raise ValueError('Subscription not found') subscription_container.remove(n) security.declarePrivate('unsubscribe_links_html') unsubscribe_links_html = PageTemplateFile("emailpt/unsubscribe_links.zpt", globals()) security.declarePrivate('remove_anonymous_subscription') def remove_anonymous_subscription(self, email, location, notif_type, lang): try: obj = self.getSite().restrictedTraverse(location) except: raise i18n_exception(ValueError, 'Invalid location') try: subscription_container = ISubscriptionContainer(obj) except: raise i18n_exception(ValueError, 'Invalid container') anonymous_subscriptions = [ (n, s) for n, s in subscription_container.list_with_keys() if hasattr(s, 'email') ] subscriptions = filter( lambda s: (s[1].email == email and s[1].location == location and s[ 1].notif_type == notif_type), anonymous_subscriptions) if len(subscriptions) == 1: subscription_container.remove(subscriptions[0][0]) else: raise i18n_exception(ValueError, 'Subscription not found') security.declareProtected(view, 'available_notif_types') def available_notif_types(self, location=''): if self.config['enable_instant']: yield 'instant' if self.config['enable_daily']: yield 'daily' if self.config['enable_weekly']: yield 'weekly' if self.config['enable_monthly']: yield 'monthly' security.declarePrivate('notify_maintainer') def notify_maintainer(self, ob, folder, **kwargs): """ Process and notify by email that B{p_object} has been uploaded into the B{p_folder}. """ auth_tool = self.getSite().getAuthenticationTool() emails = self.getMaintainersEmails(ob) person = self.REQUEST.AUTHENTICATED_USER.getUserName() if len(emails) > 0: maintainers_data = {} for email in emails: maintainers_data[email] = { 'ob': ob, 'here': self, 'person': auth_tool.name_from_userid(person), 'ob_edited': kwargs.get('ob_edited'), 'approved': ob.approved, 'container_basket': '%s/basketofapprovals_html' % folder.absolute_url(), } notif_logger.info('Maintainer notifications on %r', ofs_path(ob)) template = self._get_template('maintainer') self._send_notifications(maintainers_data, template) security.declarePrivate('notify_comment_maintainer') def notify_comment_maintainer(self, comment, parent, **kwargs): """ Process and notify by email that a comment B{comemnt} has been added to the object B{parent}. """ auth_tool = self.getSite().getAuthenticationTool() emails = self.getMaintainersEmails(parent) if len(emails) > 0: maintainers_data = {} for email in emails: maintainers_data[email] = { 'parent': parent, 'here': self, 'comment': comment, 'person': auth_tool.name_from_userid(comment.author), 'container_basket': '%s/basketofapprovals_html' % parent.absolute_url(), } notif_logger.info('Maintainer comment notifications on %r', ofs_path(parent)) template = self._get_template('maintainer') self._send_notifications(maintainers_data, template) security.declarePrivate('notify_administrative') def notify_administrative(self, ob, user_id, ob_edited=False): """ send administrative notifications because object `ob` was added or edited by the user `user_id` """ auth_tool = self.getSite().getAuthenticationTool() subscribers_data = utils.get_subscribers_data( self, ob, notif_type='administrative', **{ 'person': auth_tool.name_from_userid(user_id), 'ob_edited': ob_edited, 'approved': ob.approved, 'container_basket': '%s/basketofapprovals_html' % ob.aq_parent.absolute_url(), }) if len(subscribers_data.keys()) > 0: notif_logger.info('Administrative notifications on %r', ofs_path(ob)) template = self._get_template('administrative') self._send_notifications(subscribers_data, template) security.declarePrivate('notify_comment_administrative') def notify_comment_administrative(self, comment, parent, user_id): """ send administrative notifications because a comment was added to object `ob` by the user `user_id` """ auth_tool = self.getSite().getAuthenticationTool() subscribers_data = utils.get_subscribers_data( self, parent, notif_type='administrative', **{ 'comment': comment, 'parent': parent, 'here': self, 'person': auth_tool.name_from_userid(user_id), }) if len(subscribers_data.keys()) > 0: notif_logger.info('Administrative comment notifications on %r', ofs_path(parent)) template = self._get_template('administrative') self._send_notifications(subscribers_data, template) security.declarePrivate('notify_instant') def notify_instant(self, ob, user_id, ob_edited=False): """ send instant notifications because object `ob` was changed by the user `user_id` """ if not self.config['enable_instant']: return # Don't send notifications if the object is unapproved, but store them # into a queue to send them later when it becomes approved if not ob.approved: return auth_tool = self.getSite().getAuthenticationTool() subscribers_data = utils.get_subscribers_data( self, ob, **{ 'person': auth_tool.name_from_userid(user_id), 'ob_edited': ob_edited, }) if len(subscribers_data.keys()) > 0: notif_logger.info('Instant notifications on %r', ofs_path(ob)) template = self._get_template('instant') self._send_notifications(subscribers_data, template) security.declarePrivate('notify_comment_instant') def notify_comment_instant(self, comment, parent, user_id): """ send instant notifications because a comment was added to object `ob` by the user `user_id` """ if not self.config['enable_instant']: return # Don't send notifications if the object is unapproved, but store them # into a queue to send them later when it becomes approved if not parent.approved: return auth_tool = self.getSite().getAuthenticationTool() subscribers_data = utils.get_subscribers_data( self, parent, **{ 'comment': comment, 'parent': parent, 'person': auth_tool.name_from_userid(user_id), }) if len(subscribers_data.keys()) > 0: notif_logger.info('Comment instant notifications on %r', ofs_path(parent)) template = self._get_template('instant') self._send_notifications(subscribers_data, template) security.declarePrivate('notify_account_modification') def notify_account_modification(self, email, obj, username=None, new_roles=[], removed_roles=[]): """ Send notification that the user received or lost one or more roles in the specified location """ email_data = { email: { 'new_roles': new_roles, 'removed_roles': removed_roles, 'username': username, 'obj': obj, } } notif_logger.info('Account modification notification on %s' % self.getSite().getId()) template = self._get_template('account_modified') self._send_notifications(email_data, template) def _get_template(self, name): template = self._getOb('emailpt_%s' % name, None) if template is not None: return template.render_email template = self._getOb(name, None) if template is not None: return template.render_email template = email_templates.get(name, None) if template is not None: return template.render_email raise ValueError('template for %r not found' % name) def _send_notifications(self, messages_by_email, template): """ Send the notifications described in the `messages_by_email` data structure, using the specified EmailTemplate. `messages_by_email` should be a dictionary, keyed by email address. The values should be dictionaries suitable to be passed as kwargs (options) to the template. """ portal = self.getSite() email_tool = portal.getEmailTool() addr_from = email_tool.get_addr_from() for addr_to, kwargs in messages_by_email.iteritems(): translate = self.portal_i18n.get_translation kwargs.update({'portal': portal, '_translate': translate}) mail_data = template(**kwargs) notif_logger.info('.. sending notification to %r', addr_to) utils.send_notification(email_tool, addr_from, addr_to, mail_data['subject'], mail_data['body_text']) def _send_newsletter(self, notif_type, when_start, when_end): """ We'll look in the ``Products.Naaya.NySite.getActionLogger`` for object creation/modification log entries. Then we'll send notifications for the period between `when_start` and `when_end` using the `notif_type` template. """ notif_logger.info( 'Notifications newsletter on site %r, type %r, ' 'from %s to %s', ofs_path(self.getSite()), notif_type, when_start, when_end) objects_by_email = {} langs_by_email = {} subscriptions_by_email = {} anonymous_users = {} for log_type, ob in utils.get_modified_objects(self.getSite(), when_start, when_end): notif_logger.info('.. modified object: %r', ofs_path(ob)) for subscription in utils.fetch_subscriptions(ob, inherit=True): if subscription.notif_type != notif_type: continue if not subscription.check_permission(ob): continue email = subscription.get_email(ob) if email is None: continue content_types = getattr(subscription, 'content_types', []) if content_types and ob.meta_type not in content_types: continue notif_logger.info('.. .. sending newsletter to %r', email) objects_by_email.setdefault(email, []).append({ 'ob': ob, 'type': log_type, }) langs_by_email[email] = subscription.lang subscriptions_by_email[email] = subscription anonymous_users[email] = isinstance(subscription, AnonymousSubscription) messages_by_email = {} for email in objects_by_email: messages_by_email[email] = { 'objs': objects_by_email[email], '_lang': langs_by_email[email], 'subscription': subscriptions_by_email[email], 'here': self, 'anonymous': anonymous_users[email] } template = self._get_template(notif_type) self._send_notifications(messages_by_email, template) def _cron_heartbeat(self, when): transaction.commit() # commit earlier stuff; fresh transaction transaction.get().note('notifications cron at %s' % ofs_path(self)) # Clean temporary subscriptions after a week: if self.config.get('enable_anonymous', False): a_week_ago = when - timedelta(weeks=1) for tmp_subscription in self.pending_anonymous_subscriptions[:]: if tmp_subscription.datetime <= a_week_ago: self.pending_anonymous_subscriptions.remove( tmp_subscription) # daily newsletter ### if self.config['enable_daily']: # calculate the most recent daily newsletter time daily_time = time(hour=self.config['daily_hour']) latest_daily = datetime.combine(when.date(), daily_time) if latest_daily > when: latest_daily -= timedelta(days=1) # check if we should send a daily newsletter prev_daily = self.timestamps.get('daily', when - timedelta(days=1)) if prev_daily < latest_daily < when: self._send_newsletter('daily', prev_daily, when) self.timestamps['daily'] = when # weekly newsletter ### if self.config['enable_weekly']: # calculate the most recent weekly newsletter time weekly_time = time(hour=self.config['daily_hour']) t = datetime.combine(when.date(), weekly_time) days_delta = self.config['weekly_day'] - t.isoweekday() latest_weekly = t + timedelta(days=days_delta) if latest_weekly > when: latest_weekly -= timedelta(weeks=1) # check if we should send a weekly newsletter prev_weekly = self.timestamps.get('weekly', when - timedelta(weeks=1)) if prev_weekly < latest_weekly < when: self._send_newsletter('weekly', prev_weekly, when) self.timestamps['weekly'] = when # monthly newsletter ### if self.config['enable_monthly']: # calculate the most recent monthly newsletter time monthly_time = time(hour=self.config['monthly_hour']) the_day = utils.set_day_of_month(when.date(), self.config['monthly_day']) latest_monthly = datetime.combine(the_day, monthly_time) if latest_monthly > when: latest_monthly = utils.minus_one_month(latest_monthly) # check if we should send a monthly newsletter prev_monthly = self.timestamps.get('monthly', utils.minus_one_month(when)) if prev_monthly < latest_monthly < when: self._send_newsletter('monthly', prev_monthly, when) self.timestamps['monthly'] = when transaction.commit() # make sure our timestamp updates are saved def index_html(self, RESPONSE): """ redirect to admin page """ RESPONSE.redirect(self.absolute_url() + '/my_subscriptions_html') security.declareProtected(view, 'my_subscriptions_html') my_subscriptions_html = NaayaPageTemplateFile( 'zpt/index', globals(), 'naaya.core.notifications.my_subscriptions') security.declarePrivate('list_user_subscriptions') def user_subscriptions(self, user, cutoff_level=None): """ Returns all user subscriptions in the portal. Use with caution as this iterates almost all the objects in site. You can use `cutoff_level` to limit the depth. """ out = [] user_id = user.getId() for obj, n, subscription in utils.walk_subscriptions( self.getSite(), cutoff_level): if not isinstance(subscription, AccountSubscription): continue if subscription.user_id != user_id: continue out.append({ 'object': obj, 'notif_type': subscription.notif_type, 'content_types': getattr(subscription, 'content_types', []), 'lang': subscription.lang }) return out security.declareProtected(view, 'user_not_found') def user_not_found(self, REQUEST): """ Returns True if the user is not Anonymous, but is still not found by the AuthenticationTool (i.e. is maybe defined in the Zope root) """ user = REQUEST.AUTHENTICATED_USER if not isinstance(user, basestring): # with LDAP authentication, user is LDAP user instance user = user.id acl_tool = self.getAuthenticationTool() if acl_tool.get_user_with_userid(user) is None: return True security.declareProtected(view, 'list_my_subscriptions') def list_my_subscriptions(self, REQUEST): """ Returns a list of mappings (location, notif_type, lang) for all subscriptions of logged-in user """ user = REQUEST.AUTHENTICATED_USER if user.getId() is None and not self.config.get( 'enable_anonymous', False): raise Unauthorized # to force login subscriptions = self.user_subscriptions(user) for subscription in subscriptions: subscription['location'] = path_in_site(subscription['object']) del subscription['object'] return subscriptions security.declareProtected(view, 'my_first_subscription') def get_location_subscription(self, location, notif_type=None): """ Returns the first of the authenticated user's subscriptions in location """ for subscription in self.list_my_subscriptions(self.REQUEST): if subscription['location'] == location: if notif_type: if subscription['notif_type'] == notif_type: return subscription else: return subscription security.declareProtected(view, 'subscribe_me') def subscribe_me(self, REQUEST, location, notif_type, lang=None, content_types=[]): """ add subscription for currently-logged-in user """ # Even if some content types were selected (by turning off javascript) # they should be ignored, no filtering in administrative notifications if notif_type == 'administrative': content_types = [] if isinstance(content_types, basestring): content_types = [content_types] if lang is None: lang = self.gl_get_selected_language() REQUEST.form['lang'] = lang user_id = REQUEST.AUTHENTICATED_USER.getId() if location == '/': location = '' if user_id is None and not self.config.get('enable_anonymous', False): raise Unauthorized # to force login try: if user_id: self.add_account_subscription(user_id, location, notif_type, lang, content_types) if content_types: self.setSessionInfoTrans( 'You will receive ${notif_type} notifications' ' for any changes in "${location}" for objects of ' 'types ${content_types}.', notif_type=notif_type, location=location or self.getSite().title, content_types=', '.join(content_types)) else: self.setSessionInfoTrans( 'You will receive ${notif_type} notifications' ' for any changes in "${location}".', notif_type=notif_type, location=location) else: self.add_anonymous_subscription(**dict(REQUEST.form)) self.setSessionInfoTrans( 'An activation e-mail has been sent to ${email}. ' 'Follow the instructions to subscribe to ${notif_type} ' 'notifications for any changes in "${location}".', notif_type=notif_type, location=location, content_types=content_types, email=REQUEST.form.get('email')) except ValueError, msg: self.setSessionErrors([unicode(msg)]) return REQUEST.RESPONSE.redirect(self.absolute_url() + '/my_subscriptions_html')
class Tokenable(Entity): """Question class""" tokens_opposition = CompositeMultipleProperty('tokens_opposition') tokens_support = CompositeMultipleProperty('tokens_support') def __init__(self, **kwargs): super(Tokenable, self).__init__(**kwargs) self.set_data(kwargs) self.allocated_tokens = OOBTree() self.len_allocated_tokens = PersistentDict({}) def add_token(self, user, evaluation_type): user_oid = get_oid(user) if user_oid in self.allocated_tokens: self.remove_token(user) self.allocated_tokens[user_oid] = evaluation_type self.len_allocated_tokens.setdefault(evaluation_type, 0) self.len_allocated_tokens[evaluation_type] += 1 def remove_token(self, user): user_oid = get_oid(user) if user_oid in self.allocated_tokens: evaluation_type = self.allocated_tokens.pop(user_oid) self.len_allocated_tokens.setdefault(evaluation_type, 0) self.len_allocated_tokens[evaluation_type] -= 1 def evaluators(self, evaluation_type=None): if evaluation_type: return [ get_obj(key) for value, key in self.allocated_tokens.byValue( evaluation_type) ] return [get_obj(key) for key in self.allocated_tokens.keys()] def evaluation(self, user): user_oid = get_oid(user, None) return self.allocated_tokens.get(user_oid, None) def remove_tokens(self, force=False): evaluators = self.evaluators() for user in evaluators: user.remove_token(self) if force: self.remove_token(user) def user_has_token(self, user, root=None): if hasattr(user, 'has_token'): return user.has_token(self, root) return False def init_support_history(self): # [(user_oid, date, support_type), ...], support_type = {1:support, 0:oppose, -1:withdraw} if not hasattr(self, '_support_history'): setattr(self, '_support_history', PersistentList()) @property def len_support(self): return self.len_allocated_tokens.get(Evaluations.support, 0) @property def len_opposition(self): return self.len_allocated_tokens.get(Evaluations.oppose, 0)
class SearchableEntity(VisualisableElement, Entity): """ A Searchable entity is an entity that can be searched""" templates = { 'default': 'novaideo:templates/views/default_result.pt', 'bloc': 'novaideo:templates/views/default_result.pt' } def __init__(self, **kwargs): super(SearchableEntity, self).__init__(**kwargs) self.keywords = PersistentList() @property def is_published(self): return 'published' in self.state @property def is_workable(self): return self.is_published @property def relevant_data(self): return [ getattr(self, 'title', ''), getattr(self, 'description', ''), ', '.join(getattr(self, 'keywords', [])) ] def set_source_data(self, source_data): if not hasattr(self, 'source_data'): self.source_data = PersistentDict({}) app_name = source_data.get('app_name') self.source_data.setdefault(app_name, {}) self.source_data[app_name] = source_data def get_source_data(self, app_id): if not hasattr(self, 'source_data'): return {} return self.source_data.get(app_id, {}) def is_managed(self, root): return True def get_title(self, user=None): return getattr(self, 'title', '') def _init_presentation_text(self): pass def get_release_date(self): return getattr(self, 'release_date', self.modified_at) def presentation_text(self, nb_characters=400): return getattr(self, 'description', "")[:nb_characters] + '...' def get_more_contents_criteria(self): "return specific query, filter values" return None, { 'metadata_filter': { 'states': ['published'], 'keywords': list(self.keywords) } }
class WatcherList(object): """Adapter for lists of watchers. The lists are stored on the content objects that are being watched. A not yet implemented idea for Watchers: perhaps for each watcher keep some configuration like this: - wants plain/html - list of mails they are interested in; for xm that could be: task-started (for assignees) and task-completed (for creator); an empty list means: give me everything. """ implements(IWatcherList) ANNO_KEY = 'collective.watcherlist' def __init__(self, context): self.context = context annotations = IAnnotations(self.context) self.__mapping = annotations.get(self.ANNO_KEY, None) if self.__mapping is None: info = dict( watchers=PersistentList(), extra_addresses=PersistentList()) self.__mapping = PersistentDict(info) annotations[self.ANNO_KEY] = self.__mapping def __get_watchers(self): return self.__mapping.get('watchers') def __set_watchers(self, v): if not isinstance(v, PersistentList): v = PersistentList(v) self.__mapping['watchers'] = v watchers = property(__get_watchers, __set_watchers) def __get_extra_addresses(self): """Extra email addresses """ return self.__mapping.get('extra_addresses') def __set_extra_addresses(self, v): if not isinstance(v, PersistentList): v = PersistentList(v) self.__mapping['extra_addresses'] = v extra_addresses = property(__get_extra_addresses, __set_extra_addresses) def __get_send_emails(self): """Should emails be sent? The parent of the context may have a setting for this. In the context we may or may not wish to override this. For example, in the case of Poi we only set this on the tracker, not on individual issues. """ setting = self.__mapping.get('send_emails', _marker) if setting is not _marker: # We have an explicit setting. return setting # The context has no explicit setting, so we ask the parent. context = aq_inner(self.context) parent_list = IWatcherList(aq_parent(context), None) if parent_list is not None: return parent_list.send_emails # No explicit setting, so we fall back to the default: yes, we # send emails. return True def __set_send_emails(self, v): if not isinstance(v, bool): v = bool(v) self.__mapping['send_emails'] = v send_emails = property(__get_send_emails, __set_send_emails) def __get_allow_recursive(self): return self.__mapping.get('allow_recursive', True) def __set_allow_recursive(self, v): if not isinstance(v, bool): v = bool(v) self.__mapping['allow_recursive'] = v allow_recursive = property(__get_allow_recursive, __set_allow_recursive) def append(self, item): notify(event.ToggleWatchingEvent(self.context)) notify(event.AddedToWatchingEvent(self.context)) self.watchers.append(item) def remove(self, item): notify(event.ToggleWatchingEvent(self.context)) notify(event.RemovedFromWatchingEvent(self.context)) self.watchers.remove(item) def toggle_watching(self): """Add or remove the current authenticated member from the watchers. Taken from PoiIssue. If the current value is a tuple, we keep it that way. """ memship = getToolByName(self.context, 'portal_membership', None) if memship is None: return if memship.isAnonymousUser(): return member = memship.getAuthenticatedMember() member_id = member.getId() watchers = self.watchers if isinstance(watchers, tuple): watchers = list(watchers) as_tuple = True else: as_tuple = False if member_id in self.watchers: notify(event.ToggleWatchingEvent(self.context)) notify(event.RemovedFromWatchingEvent(self.context)) watchers.remove(member_id) else: notify(event.ToggleWatchingEvent(self.context)) notify(event.AddedToWatchingEvent(self.context)) watchers.append(member_id) if as_tuple: self.watchers = tuple(watchers) else: self.watchers = watchers def isWatching(self): """ Determine if the current user is watching this issue or not. Taken from PoiIssue. """ memship = getToolByName(self.context, 'portal_membership', None) if memship is None: return False member = memship.getAuthenticatedMember() if member is None: return False return member.getId() in self.watchers @property def addresses(self): """ Upon activity for the given issue, get the list of email addresses to which notifications should be sent. May return an empty list if notification is turned off. If issue is given, the issue poster and any watchers will also be included. Taken from PoiTracker. Note that we currently return only email addresses, without any full names. That is what Poi has been doing, and it makes a few things simpler. """ if not self.send_emails: return () # make sure no duplicates are added addresses = sets.Set() context = aq_inner(self.context) memship = getToolByName(context, 'portal_membership', None) if memship is None: # Okay, either we are in a simple unit test, or someone is # using this package outside of CMF/Plone. We should # assume the watchers are simple email addresses. addresses.union_update(self.watchers) else: addresses.union_update([get_member_email(w, memship) for w in self.watchers]) addresses.union_update(self.extra_addresses) # Discard invalid addresses: addresses.discard(None) # Discard current user: email = get_member_email() addresses.discard(email) if self.allow_recursive: # Get addresses from parent (might be recursive). parent_list = IWatcherList(aq_parent(context), None) if parent_list is not None: addresses.union_update(parent_list.addresses) return tuple(addresses) def send(self, view_name, only_these_addresses=None, **kw): """Send mail to our addresses using browser view 'view_name'. view_name is the name of a browser view for the context. We use that to get the contents and subject of the email. only_these_addresses is a list of addresses; this forces sending only to those addresses and ignoring all others. Any keyword arguments will be passed along to the update method of that view. """ context = aq_inner(self.context) if only_these_addresses is None: addresses = self.addresses else: addresses = only_these_addresses if not addresses: logger.info("No addresses found.") return if isinstance(addresses, basestring): addresses = [addresses] immediate = kw.pop('immediate', False) request = context.REQUEST mail_content = getMultiAdapter((context, request), name=view_name) mail_content.update(**kw) message = mail_content.prepare_email_message() if not message: logger.warn("Not sending empty email.") return subject = mail_content.subject simple_send_mail(message, addresses, subject, immediate=immediate)
class Taxonomy(SimpleItem): order = None count = None version = None def __init__(self, name, title, default_language): self.data = PersistentDict() self.order = PersistentDict() self.count = PersistentDict() self.version = PersistentDict() self.name = name self.title = title self.default_language = default_language @property def sm(self): return api.portal.get().getSiteManager() def __call__(self, context): if not self.data: return Vocabulary(self.name, {}, {}, {}, 2) request = getattr(context, "REQUEST", None) language = self.getCurrentLanguage(request) return self.makeVocabulary(language) @property @ram.cache(lambda method, self: (self.name, self.data._p_mtime)) def inverted_data(self): inv_data = {} for (language, elements) in self.data.items(): inv_data[language] = {} for (path, identifier) in elements.items(): inv_data[language][identifier] = path return inv_data def getShortName(self): return self.name.split('.')[-1] def getGeneratedName(self): return 'collective.taxonomy.generated.' + self.getShortName() def getVocabularyName(self): return 'collective.taxonomy.' + self.getShortName() def makeVocabulary(self, language): self._fixup() data = self.data.get(language, {}) order = self.order.get(language) version = self.version.get(language, 1) inverted_data = self.inverted_data.get(language, {}) return Vocabulary(self.name, data, inverted_data, order, version) def getCurrentLanguage(self, request): language = get_lang_code() if language in self.data: return language elif self.default_language in self.data: return self.default_language else: # our best guess! return self.data.keys()[0] def getLanguages(self): return tuple(self.data) def iterLanguage(self, language=None): if language is None: language = self.default_language vocabulary = self.makeVocabulary(language) for path, identifier in vocabulary.iterEntries(): parent_path = path.rsplit(PATH_SEPARATOR, 1)[0] if parent_path: parent = vocabulary.getTermByValue(parent_path) else: parent = None yield path, identifier, parent def registerBehavior(self, **kwargs): new_args = copy(kwargs) new_args['name'] = self.getGeneratedName() new_args['title'] = self.title new_args['description'] = kwargs.get('field_description', u'') new_args['field_description'] = new_args['description'] behavior = TaxonomyBehavior(**new_args) self.sm.registerUtility(behavior, IBehavior, name=self.getGeneratedName()) behavior.addIndex() behavior.activateSearchable() def cleanupFTI(self): """Cleanup the FTIs""" generated_name = self.getGeneratedName() for (name, fti) in self.sm.getUtilitiesFor(IDexterityFTI): if generated_name in fti.behaviors: fti.behaviors = [behavior for behavior in fti.behaviors if behavior != generated_name] modified(fti, DexterityFTIModificationDescription("behaviors", '')) def updateBehavior(self, **kwargs): behavior_name = self.getGeneratedName() short_name = self.getShortName() utility = self.sm.queryUtility(IBehavior, name=behavior_name) if utility: utility.deactivateSearchable() utility.activateSearchable() if 'field_title' in kwargs: utility.title = kwargs.pop('field_title') for k, v in kwargs.items(): setattr(utility, k, v) delattr(generated, short_name) for (name, fti) in self.sm.getUtilitiesFor(IDexterityFTI): if behavior_name in fti.behaviors: modified(fti, DexterityFTIModificationDescription("behaviors", '')) def unregisterBehavior(self): behavior_name = self.getGeneratedName() utility = self.sm.queryUtility(IBehavior, name=behavior_name) if utility is None: return self.cleanupFTI() utility.removeIndex() utility.deactivateSearchable() utility.unregisterInterface() self.sm.unregisterUtility(utility, IBehavior, name=behavior_name) def clean(self): self.data.clear() def add(self, language, value, key): self._fixup() tree = self.data.get(language) if tree is None: tree = self.data[language] = OOBTree() else: # Make sure we update the modification time. self.data[language] = tree update = key in tree tree[key] = value order = self.order.get(language) if order is None: order = self.order[language] = IOBTree() count = self.count[language] = 0 else: if update: pop_value(tree, key) count = self.count[language] + 1 self.count[language] = count order[count] = key def update(self, language, items, clear=False): self._fixup() tree = self.data.setdefault(language, OOBTree()) if clear: tree.clear() # A new tree always uses the newest version. if not tree: version = self.version[language] = 2 else: version = self.version.get(language, 1) order = self.order.setdefault(language, IOBTree()) count = self.count.get(language, 0) if clear: order.clear() count = 0 # Always migrate to newest version. if version == 1: def fix(path): return path.replace(LEGACY_PATH_SEPARATOR, PATH_SEPARATOR) for i in list(order): path = order[i] order[i] = fix(path) for path in list(tree): value = tree.pop(path) tree[fix(path)] = value version = self.version[language] = 2 logger.info( "Taxonomy '%s' upgraded to version %d for language '%s'." % ( self.name, version, language ) ) # Make sure we update the modification time. self.data[language] = tree # The following structure is used to expunge updated entries. inv = {} if not clear: for i, key in order.items(): inv[key] = i seen = set() for key, value in items: if key in seen: logger.warning("Duplicate key entry: %r" % (key, )) continue seen.add(key) update = key in tree tree[key] = value order[count] = key count += 1 # If we're updating, then we have to pop out the old ordering # information in order to maintain relative ordering of new items. if update: i = inv.get(key) if i is not None: del order[i] self.count[language] = count def translate(self, msgid, mapping=None, context=None, target_language=None, default=None, msgid_plural=None, default_plural=None, number=None): if target_language is None or \ target_language not in self.inverted_data: target_language = str(api.portal.get_current_language()) if msgid not in self.inverted_data[target_language]: return '' if self.version is not None and self.version.get(target_language) != 2: path_sep = LEGACY_PATH_SEPARATOR else: path_sep = PATH_SEPARATOR path = self.inverted_data[target_language][msgid] pretty_path = path[1:].replace(path_sep, PRETTY_PATH_SEPARATOR) if mapping is not None and mapping.get(NODE): pretty_path = pretty_path.rsplit(PRETTY_PATH_SEPARATOR, 1)[-1] return pretty_path def _fixup(self): # due to compatibility reasons this method fixes data structure # for old Taxonomy instances. # XXX: remove this in version 2.0 to prevent write on read if self.order is None: safeWrite(self, getRequest()) self.order = PersistentDict() self.count = PersistentDict() if self.version is None: safeWrite(self, getRequest()) self.version = PersistentDict()