class Variables(ContainerTab): """A container for variable definitions""" meta_type = 'Workflow Variables' all_meta_types = ({'name':VariableDefinition.meta_type, 'action':'addVariable', },) _manage_variables = DTMLResource('dtml/variables', globals()) def manage_main(self, REQUEST, manage_tabs_message=None): ''' ''' return self._manage_variables( REQUEST, management_view='Variables', manage_tabs_message=manage_tabs_message, ) def addVariable(self, id, REQUEST=None): ''' ''' vdef = VariableDefinition(id) self._setObject(id, vdef) if REQUEST is not None: return self.manage_main(REQUEST, 'Variable added.') def deleteVariables(self, ids, REQUEST=None): ''' ''' for id in ids: self._delObject(id) if REQUEST is not None: return self.manage_main(REQUEST, 'Variable(s) removed.') def _checkId(self, id, allow_dup=0): wf_def = aq_parent(aq_inner(self)) if id == wf_def.state_var: raise 'Bad Request', '"%s" is used for keeping state.' % id return ContainerTab._checkId(self, id, allow_dup) def getStateVar(self): wf_def = aq_parent(aq_inner(self)) return wf_def.state_var def setStateVar(self, id, REQUEST=None): ''' ''' wf_def = aq_parent(aq_inner(self)) if id != wf_def.state_var: self._checkId(id) wf_def.state_var = str(id) if REQUEST is not None: return self.manage_main(REQUEST, 'Set state variable.')
class States(ContainerTab): """A container for state definitions""" meta_type = 'Workflow States' security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) all_meta_types = ({ 'name': StateDefinition.meta_type, 'action': 'addState', }, ) _manage_states = DTMLResource('dtml/states', globals()) def manage_main(self, REQUEST, manage_tabs_message=None): ''' ''' return self._manage_states( REQUEST, management_view='States', manage_tabs_message=manage_tabs_message, ) def addState(self, id, REQUEST=None): ''' ''' sdef = StateDefinition(id) self._setObject(id, sdef) if REQUEST is not None: return self.manage_main(REQUEST, 'State added.') def deleteStates(self, ids, REQUEST=None): ''' ''' for id in ids: self._delObject(id) if REQUEST is not None: return self.manage_main(REQUEST, 'State(s) removed.') def setInitialState(self, id=None, ids=None, REQUEST=None): ''' ''' if not id: if len(ids) != 1: raise ValueError, 'One and only one state must be selected' id = ids[0] id = str(id) aq_parent(aq_inner(self)).initial_state = id if REQUEST is not None: return self.manage_main(REQUEST, 'Initial state selected.')
class PropertiesTool(UniqueObject, SimpleItem, ActionProviderBase): implements(IPropertiesTool) __implements__ = (z2IPropertiesTool, ActionProviderBase.__implements__) id = 'portal_properties' meta_type = 'Default Properties Tool' security = ClassSecurityInfo() manage_options = (ActionProviderBase.manage_options + ({ 'label': 'Overview', 'action': 'manage_overview' }, ) + SimpleItem.manage_options) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLResource('dtml/explainPropertiesTool', globals()) # # 'portal_properties' interface methods # security.declareProtected(ManagePortal, 'editProperties') def editProperties(self, props): '''Change portal settings''' aq_parent(aq_inner(self)).manage_changeProperties(props) self.MailHost.smtp_host = props['smtp_server'] if hasattr(self, 'propertysheets'): ps = self.propertysheets if hasattr(ps, 'props'): ps.props.manage_changeProperties(props) def title(self): return self.aq_inner.aq_parent.title def smtp_server(self): return self.MailHost.smtp_host
class Worklists(ContainerTab): """A container for worklist definitions""" meta_type = 'Worklists' security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) all_meta_types = ({ 'name': WorklistDefinition.meta_type, 'action': 'addWorklist', }, ) _manage_worklists = DTMLResource('dtml/worklists', globals()) def manage_main(self, REQUEST, manage_tabs_message=None): ''' ''' return self._manage_worklists( REQUEST, management_view='Worklists', manage_tabs_message=manage_tabs_message, ) def addWorklist(self, id, REQUEST=None): ''' ''' qdef = WorklistDefinition(id) self._setObject(id, qdef) if REQUEST is not None: return self.manage_main(REQUEST, 'Worklist added.') def deleteWorklists(self, ids, REQUEST=None): ''' ''' for id in ids: self._delObject(id) if REQUEST is not None: return self.manage_main(REQUEST, 'Worklist(s) removed.')
class WorkflowUIMixin: ''' ''' security = ClassSecurityInfo() security.declareProtected(ManagePortal, 'manage_properties') manage_properties = DTMLResource('dtml/workflow_properties', globals()) manage_groups = PageTemplateResource('dtml/workflow_groups.pt', globals()) security.declareProtected(ManagePortal, 'setProperties') def setProperties(self, title, manager_bypass=0, props=None, REQUEST=None): """Sets basic properties. """ self.title = str(title) self.manager_bypass = manager_bypass and 1 or 0 g = Guard() if g.changeFromProperties(props or REQUEST): self.creation_guard = g else: self.creation_guard = None if REQUEST is not None: return self.manage_properties( REQUEST, manage_tabs_message='Properties changed.') _permissions_form = DTMLResource('dtml/workflow_permissions', globals()) security.declareProtected(ManagePortal, 'manage_permissions') def manage_permissions(self, REQUEST, manage_tabs_message=None): """Displays the form for choosing which permissions to manage. """ return self._permissions_form(REQUEST, management_view='Permissions', manage_tabs_message=manage_tabs_message, ) security.declareProtected(ManagePortal, 'addManagedPermission') def addManagedPermission(self, p, REQUEST=None): """Adds to the list of permissions to manage. """ if p in self.permissions: raise ValueError, 'Already a managed permission: ' + p if REQUEST is not None and p not in self.getPossiblePermissions(): raise ValueError, 'Not a valid permission name:' + p self.permissions = self.permissions + (p,) if REQUEST is not None: return self.manage_permissions( REQUEST, manage_tabs_message='Permission added.') security.declareProtected(ManagePortal, 'delManagedPermissions') def delManagedPermissions(self, ps, REQUEST=None): """Removes from the list of permissions to manage. """ if ps: l = list(self.permissions) for p in ps: l.remove(p) self.permissions = tuple(l) if REQUEST is not None: return self.manage_permissions( REQUEST, manage_tabs_message='Permission(s) removed.') security.declareProtected(ManagePortal, 'getPossiblePermissions') def getPossiblePermissions(self): """Returns the list of all permissions that can be managed. """ # possible_permissions is in AccessControl.Role.RoleManager. return list(self.possible_permissions()) security.declareProtected(ManagePortal, 'getGroups') def getGroups(self): """Returns the names of groups managed by this workflow. """ return tuple(self.groups) security.declareProtected(ManagePortal, 'getAvailableGroups') def getAvailableGroups(self): """Returns a list of available group names. """ gf = aq_get( self, '__allow_groups__', None, 1 ) if gf is None: return () try: groups = gf.searchGroups() except AttributeError: return () else: return [g['id'] for g in groups] security.declareProtected(ManagePortal, 'addGroup') def addGroup(self, group, RESPONSE=None): """Adds a group by name. """ if group not in self.getAvailableGroups(): raise ValueError(group) self.groups = self.groups + (group,) if RESPONSE is not None: RESPONSE.redirect( "%s/manage_groups?manage_tabs_message=Added+group." % self.absolute_url()) security.declareProtected(ManagePortal, 'delGroups') def delGroups(self, groups, RESPONSE=None): """Removes groups by name. """ self.groups = tuple([g for g in self.groups if g not in groups]) if RESPONSE is not None: RESPONSE.redirect( "%s/manage_groups?manage_tabs_message=Groups+removed." % self.absolute_url()) security.declareProtected(ManagePortal, 'getAvailableRoles') def getAvailableRoles(self): """Returns the acquired roles mixed with base_cms roles. """ roles = list(self.valid_roles()) for role in getDefaultRolePermissionMap().keys(): if role not in roles: roles.append(role) roles.sort() return roles security.declareProtected(ManagePortal, 'getRoles') def getRoles(self): """Returns the list of roles managed by this workflow. """ roles = self.roles if roles is not None: return roles roles = getDefaultRolePermissionMap().keys() if roles: # Map the base_cms roles by default. roles.sort() return roles return self.valid_roles() security.declareProtected(ManagePortal, 'setRoles') def setRoles(self, roles, RESPONSE=None): """Changes the list of roles mapped to groups by this workflow. """ avail = self.getAvailableRoles() for role in roles: if role not in avail: raise ValueError(role) self.roles = tuple(roles) if RESPONSE is not None: RESPONSE.redirect( "%s/manage_groups?manage_tabs_message=Roles+changed." % self.absolute_url()) security.declareProtected(ManagePortal, 'getGuard') def getGuard(self): """Returns the initiation guard. If no init guard has been created, returns a temporary object. """ if self.creation_guard is not None: return self.creation_guard else: return Guard().__of__(self) # Create a temporary guard. security.declarePublic('guardExprDocs') def guardExprDocs(self): """Returns documentation on guard expressions. """ text = resource_string('doc/expressions.stx', globals()) from DocumentTemplate.DT_Var import structured_text return structured_text(text)
class DefaultDublinCoreImpl(PropertyManager): """ Mix-in class which provides Dublin Core methods. """ implements(IDublinCore, ICatalogableDublinCore, IMutableDublinCore) __implements__ = (z2IDublinCore, z2ICatalogableDublinCore, z2IMutableDublinCore) security = ClassSecurityInfo() def __init__(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='', rights=''): now = DateTime() self.creation_date = now self.modification_date = now self.creators = () self._editMetadata(title, subject, description, contributors, effective_date, expiration_date, format, language, rights) # # Set-modification-date-related methods. # In DefaultDublinCoreImpl for lack of a better place. # # Class variable default for an upgrade. modification_date = None security.declarePrivate('notifyModified') def notifyModified(self): """ Take appropriate action after the resource has been modified. Update creators and modification_date. """ self.addCreator() self.setModificationDate() security.declareProtected(ModifyPortalContent, 'addCreator') def addCreator(self, creator=None): """ Add creator to Dublin Core creators. """ if creator is None: mtool = getToolByName(self, 'portal_membership', None) creator = mtool and mtool.getAuthenticatedMember().getId() # call self.listCreators() to make sure self.creators exists if creator and not creator in self.listCreators(): self.creators = self.creators + (creator, ) security.declareProtected(ModifyPortalContent, 'setModificationDate') def setModificationDate(self, modification_date=None): """ Set the date when the resource was last modified. When called without an argument, sets the date to now. """ if modification_date is None: self.modification_date = DateTime() else: self.modification_date = self._datify(modification_date) # # DublinCore interface query methods # security.declareProtected(View, 'Title') def Title(self): """ Dublin Core Title element - resource name. """ return self.title security.declareProtected(View, 'listCreators') def listCreators(self): """ List Dublin Core Creator elements - resource authors. """ if not hasattr(aq_base(self), 'creators'): # for content created with CMF versions before 1.5 owner_tuple = self.getOwnerTuple() if owner_tuple: self.creators = (owner_tuple[1], ) else: self.creators = () return self.creators security.declareProtected(View, 'Creator') def Creator(self): """ Dublin Core Creator element - resource author. """ creators = self.listCreators() return creators and creators[0] or '' security.declareProtected(View, 'Subject') def Subject(self): """ Dublin Core Subject element - resource keywords. """ return getattr(self, 'subject', ()) # compensate for *old* content security.declareProtected(View, 'Description') def Description(self): """ Dublin Core Description element - resource summary. """ return self.description security.declareProtected(View, 'Publisher') def Publisher(self): """ Dublin Core Publisher element - resource publisher. """ tool = getToolByName(self, 'portal_metadata', None) if tool is not None: return tool.getPublisher() return 'No publisher' security.declareProtected(View, 'listContributors') def listContributors(self): """ Dublin Core Contributor elements - resource collaborators. """ return self.contributors security.declareProtected(View, 'Contributors') def Contributors(self): """ Deprecated alias of listContributors. """ return self.listContributors() security.declareProtected(View, 'Date') def Date(self): """ Dublin Core Date element - default date. """ # Return effective_date if set, modification date otherwise date = getattr(self, 'effective_date', None) if date is None: date = self.modified() return date.toZone(_zone).ISO() security.declareProtected(View, 'CreationDate') def CreationDate(self): """ Dublin Core Date element - date resource created. """ # return unknown if never set properly if self.creation_date: return self.creation_date.toZone(_zone).ISO() else: return 'Unknown' security.declareProtected(View, 'EffectiveDate') def EffectiveDate(self): """ Dublin Core Date element - date resource becomes effective. """ ed = getattr(self, 'effective_date', None) return ed and ed.toZone(_zone).ISO() or 'None' security.declareProtected(View, 'ExpirationDate') def ExpirationDate(self): """ Dublin Core Date element - date resource expires. """ ed = getattr(self, 'expiration_date', None) return ed and ed.toZone(_zone).ISO() or 'None' security.declareProtected(View, 'ModificationDate') def ModificationDate(self): """ Dublin Core Date element - date resource last modified. """ return self.modified().toZone(_zone).ISO() security.declareProtected(View, 'Type') def Type(self): """ Dublin Core Type element - resource type. """ ti = self.getTypeInfo() return ti is not None and ti.Title() or 'Unknown' security.declareProtected(View, 'Format') def Format(self): """ Dublin Core Format element - resource format. """ return self.format security.declareProtected(View, 'Identifier') def Identifier(self): """ Dublin Core Identifier element - resource ID. """ # XXX: fixme using 'portal_metadata' (we need to prepend the # right prefix to self.getPhysicalPath(). return self.absolute_url() security.declareProtected(View, 'Language') def Language(self): """ Dublin Core Language element - resource language. """ return self.language security.declareProtected(View, 'Rights') def Rights(self): """ Dublin Core Rights element - resource copyright. """ return self.rights # # DublinCore utility methods # def content_type(self): """ WebDAV needs this to do the Right Thing (TM). """ return self.Format() __FLOOR_DATE = DateTime(1970, 0) # always effective security.declareProtected(View, 'isEffective') def isEffective(self, date): """ Is the date within the resource's effective range? """ pastEffective = (self.effective_date is None or self.effective_date <= date) beforeExpiration = (self.expiration_date is None or self.expiration_date >= date) return pastEffective and beforeExpiration # # CatalogableDublinCore methods # security.declareProtected(View, 'created') def created(self): """ Dublin Core Date element - date resource created. """ # allow for non-existent creation_date, existed always date = getattr(self, 'creation_date', None) return date is None and self.__FLOOR_DATE or date security.declareProtected(View, 'effective') def effective(self): """ Dublin Core Date element - date resource becomes effective. """ marker = [] date = getattr(self, 'effective_date', marker) if date is marker: date = getattr(self, 'creation_date', None) return date is None and self.__FLOOR_DATE or date __CEILING_DATE = DateTime(2500, 0) # never expires security.declareProtected(View, 'expires') def expires(self): """ Dublin Core Date element - date resource expires. """ date = getattr(self, 'expiration_date', None) return date is None and self.__CEILING_DATE or date security.declareProtected(View, 'modified') def modified(self): """ Dublin Core Date element - date resource last modified. """ date = self.modification_date if date is None: # Upgrade. date = self.bobobase_modification_time() self.modification_date = date return date security.declareProtected(View, 'getMetadataHeaders') def getMetadataHeaders(self): """ Return RFC-822-style headers. """ hdrlist = [] hdrlist.append(('Title', self.Title())) hdrlist.append(('Subject', ', '.join(self.Subject()))) hdrlist.append(('Publisher', self.Publisher())) hdrlist.append(('Description', self.Description())) hdrlist.append(('Contributors', '; '.join(self.Contributors()))) hdrlist.append(('Effective_date', self.EffectiveDate())) hdrlist.append(('Expiration_date', self.ExpirationDate())) hdrlist.append(('Type', self.Type())) hdrlist.append(('Format', self.Format())) hdrlist.append(('Language', self.Language())) hdrlist.append(('Rights', self.Rights())) return hdrlist # # MutableDublinCore methods # security.declarePrivate('_datify') def _datify(self, attrib): if attrib == 'None': attrib = None elif not isinstance(attrib, DateTime): if attrib is not None: attrib = DateTime(attrib) return attrib security.declareProtected(ModifyPortalContent, 'setTitle') def setTitle(self, title): """ Set Dublin Core Title element - resource name. """ self.title = title security.declareProtected(ModifyPortalContent, 'setCreators') def setCreators(self, creators): """ Set Dublin Core Creator elements - resource authors. """ self.creators = tuplize('creators', creators) security.declareProtected(ModifyPortalContent, 'setSubject') def setSubject(self, subject): """ Set Dublin Core Subject element - resource keywords. """ self.subject = tuplize('subject', subject) security.declareProtected(ModifyPortalContent, 'setDescription') def setDescription(self, description): """ Set Dublin Core Description element - resource summary. """ self.description = description security.declareProtected(ModifyPortalContent, 'setContributors') def setContributors(self, contributors): """ Set Dublin Core Contributor elements - resource collaborators. """ # XXX: fixme self.contributors = tuplize('contributors', contributors, semi_split) security.declareProtected(ModifyPortalContent, 'setEffectiveDate') def setEffectiveDate(self, effective_date): """ Set Dublin Core Date element - date resource becomes effective. """ self.effective_date = self._datify(effective_date) security.declareProtected(ModifyPortalContent, 'setExpirationDate') def setExpirationDate(self, expiration_date): """ Set Dublin Core Date element - date resource expires. """ self.expiration_date = self._datify(expiration_date) security.declareProtected(ModifyPortalContent, 'setFormat') def setFormat(self, format): """ Set Dublin Core Format element - resource format. """ self.format = format security.declareProtected(ModifyPortalContent, 'setLanguage') def setLanguage(self, language): """ Set Dublin Core Language element - resource language. """ self.language = language security.declareProtected(ModifyPortalContent, 'setRights') def setRights(self, rights): """ Set Dublin Core Rights element - resource copyright. """ self.rights = rights # # Management tab methods # security.declarePrivate('_editMetadata') def _editMetadata(self, title=_marker, subject=_marker, description=_marker, contributors=_marker, effective_date=_marker, expiration_date=_marker, format=_marker, language=_marker, rights=_marker): """ Update the editable metadata for this resource. """ if title is not _marker: self.setTitle(title) if subject is not _marker: self.setSubject(subject) if description is not _marker: self.setDescription(description) if contributors is not _marker: self.setContributors(contributors) if effective_date is not _marker: self.setEffectiveDate(effective_date) if expiration_date is not _marker: self.setExpirationDate(expiration_date) if format is not _marker: self.setFormat(format) if language is not _marker: self.setLanguage(language) if rights is not _marker: self.setRights(rights) security.declareProtected(ModifyPortalContent, 'manage_metadata') manage_metadata = DTMLResource('dtml/zmi_metadata', globals()) security.declareProtected(ModifyPortalContent, 'manage_editMetadata') def manage_editMetadata(self, title, subject, description, contributors, effective_date, expiration_date, format, language, rights, REQUEST): """ Update metadata from the ZMI. """ self._editMetadata(title, subject, description, contributors, effective_date, expiration_date, format, language, rights) REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_metadata' + '?manage_tabs_message=Metadata+updated.') security.declareProtected(ModifyPortalContent, 'editMetadata') def editMetadata(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='en-US', rights=''): """ Need to add check for webDAV locked resource for TTW methods. """ # as per bug #69, we cant assume they use the webdav # locking interface, and fail gracefully if they dont if hasattr(self, 'failIfLocked'): self.failIfLocked() self._editMetadata(title=title, subject=subject, description=description, contributors=contributors, effective_date=effective_date, expiration_date=expiration_date, format=format, language=language, rights=rights) self.reindexObject()
class TransitionDefinition(SimpleItem): """Transition definition""" meta_type = 'Workflow Transition' security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) title = '' description = '' new_state_id = '' trigger_type = TRIGGER_USER_ACTION guard = None actbox_name = '' actbox_url = '' actbox_category = 'workflow' var_exprs = None # A mapping. script_name = None # Executed before transition after_script_name = None # Executed after transition manage_options = ( { 'label': 'Properties', 'action': 'manage_properties' }, { 'label': 'Variables', 'action': 'manage_variables' }, ) def __init__(self, id): self.id = id def getId(self): return self.id def getGuardSummary(self): res = None if self.guard is not None: res = self.guard.getSummary() return res def getGuard(self): if self.guard is not None: return self.guard else: return Guard().__of__(self) # Create a temporary guard. def getVarExprText(self, id): if not self.var_exprs: return '' else: expr = self.var_exprs.get(id, None) if expr is not None: return expr.text else: return '' def getWorkflow(self): return aq_parent(aq_inner(aq_parent(aq_inner(self)))) def getAvailableStateIds(self): return self.getWorkflow().states.keys() def getAvailableScriptIds(self): return self.getWorkflow().scripts.keys() def getAvailableVarIds(self): return self.getWorkflow().variables.keys() _properties_form = DTMLResource('dtml/transition_properties', globals()) def manage_properties(self, REQUEST, manage_tabs_message=None): ''' ''' return self._properties_form( REQUEST, management_view='Properties', manage_tabs_message=manage_tabs_message, ) def setProperties(self, title, new_state_id, trigger_type=TRIGGER_USER_ACTION, script_name='', after_script_name='', actbox_name='', actbox_url='', actbox_category='workflow', props=None, REQUEST=None, description=''): ''' ''' self.title = str(title) self.description = str(description) self.new_state_id = str(new_state_id) self.trigger_type = int(trigger_type) self.script_name = str(script_name) self.after_script_name = str(after_script_name) g = Guard() if g.changeFromProperties(props or REQUEST): self.guard = g else: self.guard = None self.actbox_name = str(actbox_name) self.actbox_url = str(actbox_url) self.actbox_category = str(actbox_category) if REQUEST is not None: return self.manage_properties(REQUEST, 'Properties changed.') _variables_form = DTMLResource('dtml/transition_variables', globals()) def manage_variables(self, REQUEST, manage_tabs_message=None): ''' ''' return self._variables_form( REQUEST, management_view='Variables', manage_tabs_message=manage_tabs_message, ) def getVariableExprs(self): ''' get variable exprs for management UI ''' ve = self.var_exprs if ve is None: return [] else: ret = [] for key in ve.keys(): ret.append((key, self.getVarExprText(key))) return ret def getWorkflowVariables(self): ''' get all variables that are available form workflow and not handled yet. ''' wf_vars = self.getAvailableVarIds() if self.var_exprs is None: return wf_vars ret = [] for vid in wf_vars: if not self.var_exprs.has_key(vid): ret.append(vid) return ret def addVariable(self, id, text, REQUEST=None): ''' Add a variable expression. ''' if self.var_exprs is None: self.var_exprs = PersistentMapping() expr = None if text: expr = Expression(str(text)) self.var_exprs[id] = expr if REQUEST is not None: return self.manage_variables(REQUEST, 'Variable added.') def deleteVariables(self, ids=[], REQUEST=None): ''' delete a WorkflowVariable from State ''' ve = self.var_exprs for id in ids: if ve.has_key(id): del ve[id] if REQUEST is not None: return self.manage_variables(REQUEST, 'Variables deleted.') def setVariables(self, ids=[], REQUEST=None): ''' set values for Variables set by this state ''' if self.var_exprs is None: self.var_exprs = PersistentMapping() ve = self.var_exprs if REQUEST is not None: for id in ve.keys(): fname = 'varexpr_%s' % id val = REQUEST[fname] expr = None if val: expr = Expression(str(REQUEST[fname])) ve[id] = expr return self.manage_variables(REQUEST, 'Variables changed.')
class Link(PortalContent, DefaultDublinCoreImpl): """A Link. """ __implements__ = (PortalContent.__implements__, DefaultDublinCoreImpl.__implements__) meta_type = 'Link' URL_FORMAT = format = 'text/url' effective_date = expiration_date = None _isDiscussable = 1 security = ClassSecurityInfo() def __init__(self, id, title='', remote_url='', description=''): DefaultDublinCoreImpl.__init__(self) self.id = id self.title = title self.description = description self._edit(remote_url) self.format = self.URL_FORMAT security.declareProtected(ModifyPortalContent, 'manage_edit') manage_edit = DTMLResource('dtml/zmi_editLink', globals()) security.declareProtected(ModifyPortalContent, 'manage_editLink') def manage_editLink(self, remote_url, REQUEST=None): """ Update the Link via the ZMI. """ self._edit(remote_url) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_edit' + '?manage_tabs_message=Link+updated') security.declarePrivate('_edit') def _edit(self, remote_url): """ Edit the Link """ tokens = urlparse.urlparse(remote_url, 'http') if tokens[0] == 'http': if tokens[1]: # We have a nethost. All is well. url = urlparse.urlunparse(tokens) elif tokens[2:] == ('', '', '', ''): # Empty URL url = '' else: # Relative URL, keep it that way, without http: tokens = ('', '') + tokens[2:] url = urlparse.urlunparse(tokens) else: # Other scheme, keep original url = urlparse.urlunparse(tokens) self.remote_url = url security.declareProtected(ModifyPortalContent, 'edit') def edit(self, remote_url): """ Update and reindex. """ self._edit(remote_url) self.reindexObject() security.declareProtected(View, 'SearchableText') def SearchableText(self): """ text for indexing """ return "%s %s" % (self.title, self.description) security.declareProtected(View, 'getRemoteUrl') def getRemoteUrl(self): """ returns the remote URL of the Link """ return self.remote_url security.declarePrivate('_writeFromPUT') def _writeFromPUT(self, body): headers = {} headers, body = parseHeadersBody(body, headers) lines = body.split('\n') self.edit(lines[0]) headers['Format'] = self.URL_FORMAT new_subject = keywordsplitter(headers) headers['Subject'] = new_subject or self.Subject() new_contrib = contributorsplitter(headers) headers['Contributors'] = new_contrib or self.Contributors() haveheader = headers.has_key for key, value in self.getMetadataHeaders(): if not haveheader(key): headers[key] = value self._editMetadata( title=headers['Title'], subject=headers['Subject'], description=headers['Description'], contributors=headers['Contributors'], effective_date=headers['Effective_date'], expiration_date=headers['Expiration_date'], format=headers['Format'], language=headers['Language'], rights=headers['Rights'], ) ## FTP handlers security.declareProtected(ModifyPortalContent, 'PUT') def PUT(self, REQUEST, RESPONSE): """ Handle HTTP / WebDAV / FTP PUT requests. """ self.dav__init(REQUEST, RESPONSE) self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1) body = REQUEST.get('BODY', '') try: self._writeFromPUT(body) RESPONSE.setStatus(204) return RESPONSE except ResourceLockedError, msg: transaction.abort() RESPONSE.setStatus(423) return RESPONSE
class StateDefinition(SimpleItem): """State definition""" meta_type = 'Workflow State' manage_options = ( { 'label': 'Properties', 'action': 'manage_properties' }, { 'label': 'Permissions', 'action': 'manage_permissions' }, { 'label': 'Groups', 'action': 'manage_groups' }, { 'label': 'Variables', 'action': 'manage_variables' }, ) title = '' description = '' transitions = () # The ids of possible transitions. permission_roles = None # { permission: [role] or (role,) } group_roles = None # { group name : (role,) } var_values = None # PersistentMapping if set. Overrides transition exprs. security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) def __init__(self, id): self.id = id def getId(self): return self.id def getWorkflow(self): return aq_parent(aq_inner(aq_parent(aq_inner(self)))) def getTransitions(self): return filter(self.getWorkflow().transitions.has_key, self.transitions) def getTransitionTitle(self, tid): t = self.getWorkflow().transitions.get(tid, None) if t is not None: return t.title return '' def getAvailableTransitionIds(self): return self.getWorkflow().transitions.keys() def getAvailableVarIds(self): return self.getWorkflow().variables.keys() def getManagedPermissions(self): return list(self.getWorkflow().permissions) def getAvailableRoles(self): return self.getWorkflow().getAvailableRoles() def getPermissionInfo(self, p): """Returns the list of roles to be assigned to a permission. """ roles = None if self.permission_roles: roles = self.permission_roles.get(p, None) if roles is None: return {'acquired': 1, 'roles': []} else: if isinstance(roles, tuple): acq = 0 else: acq = 1 return {'acquired': acq, 'roles': list(roles)} def getGroupInfo(self, group): """Returns the list of roles to be assigned to a group. """ if self.group_roles: return self.group_roles.get(group, ()) return () _properties_form = DTMLResource('dtml/state_properties', globals()) def manage_properties(self, REQUEST, manage_tabs_message=None): """Show state properties ZMI form.""" return self._properties_form( REQUEST, management_view='Properties', manage_tabs_message=manage_tabs_message, ) def setProperties(self, title='', transitions=(), REQUEST=None, description=''): """Set the properties for this State.""" self.title = str(title) self.description = str(description) self.transitions = tuple(map(str, transitions)) if REQUEST is not None: return self.manage_properties(REQUEST, 'Properties changed.') _variables_form = DTMLResource('dtml/state_variables', globals()) def manage_variables(self, REQUEST, manage_tabs_message=None): """Show State variables ZMI form.""" return self._variables_form( REQUEST, management_view='Variables', manage_tabs_message=manage_tabs_message, ) def getVariableValues(self): """Get VariableValues for management UI.""" vv = self.var_values if vv is None: return [] else: return vv.items() def getWorkflowVariables(self): """Get all variables that are available from the workflow and not handled yet. """ wf_vars = self.getAvailableVarIds() if self.var_values is None: return wf_vars ret = [] for vid in wf_vars: if not self.var_values.has_key(vid): ret.append(vid) return ret def addVariable(self, id, value, REQUEST=None): """Add a WorkflowVariable to State.""" if self.var_values is None: self.var_values = PersistentMapping() self.var_values[id] = value if REQUEST is not None: return self.manage_variables(REQUEST, 'Variable added.') def deleteVariables(self, ids=[], REQUEST=None): """Delete a WorkflowVariable from State.""" vv = self.var_values for id in ids: if vv.has_key(id): del vv[id] if REQUEST is not None: return self.manage_variables(REQUEST, 'Variables deleted.') def setVariables(self, ids=[], REQUEST=None): """Set values for Variables set by this State.""" if self.var_values is None: self.var_values = PersistentMapping() vv = self.var_values if REQUEST is not None: for id in vv.keys(): fname = 'varval_%s' % id vv[id] = str(REQUEST[fname]) return self.manage_variables(REQUEST, 'Variables changed.') _permissions_form = DTMLResource('dtml/state_permissions', globals()) def manage_permissions(self, REQUEST, manage_tabs_message=None): """Present TTW UI for managing this State's permissions.""" return self._permissions_form( REQUEST, management_view='Permissions', manage_tabs_message=manage_tabs_message, ) def setPermissions(self, REQUEST): """Set the permissions in REQUEST for this State.""" pr = self.permission_roles if pr is None: self.permission_roles = pr = PersistentMapping() pr.clear() for p in self.getManagedPermissions(): roles = [] acquired = REQUEST.get('acquire_' + p, 0) for r in self.getAvailableRoles(): if REQUEST.get('%s|%s' % (p, r), 0): roles.append(r) roles.sort() if not acquired: roles = tuple(roles) pr[p] = roles return self.manage_permissions(REQUEST, 'Permissions changed.') def setPermission(self, permission, acquired, roles): """Set a permission for this State.""" pr = self.permission_roles if pr is None: self.permission_roles = pr = PersistentMapping() if acquired: roles = list(roles) else: roles = tuple(roles) pr[permission] = roles manage_groups = PageTemplateResource('dtml/state_groups.pt', globals()) def setGroups(self, REQUEST, RESPONSE=None): """Set the group to role mappings in REQUEST for this State. """ map = self.group_roles if map is None: self.group_roles = map = PersistentMapping() map.clear() all_roles = self.getWorkflow().getRoles() for group in self.getWorkflow().getGroups(): roles = [] for role in all_roles: if REQUEST.get('%s|%s' % (group, role), 0): roles.append(role) roles.sort() roles = tuple(roles) map[group] = roles if RESPONSE is not None: RESPONSE.redirect( "%s/manage_groups?manage_tabs_message=Groups+changed." % self.absolute_url())
class Guard(Persistent, Explicit): permissions = () roles = () groups = () expr = None security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) guardForm = DTMLResource('dtml/guard', globals()) def check(self, sm, wf_def, ob, **kw): """Checks conditions in this guard. """ u_roles = None if wf_def.manager_bypass: # Possibly bypass. u_roles = sm.getUser().getRolesInContext(ob) if 'Manager' in u_roles: return 1 if self.permissions: for p in self.permissions: if _checkPermission(p, ob): break else: return 0 if self.roles: # Require at least one of the given roles. if u_roles is None: u_roles = sm.getUser().getRolesInContext(ob) for role in self.roles: if role in u_roles: break else: return 0 if self.groups: # Require at least one of the specified groups. u = sm.getUser() b = aq_base(u) if hasattr(b, 'getGroupsInContext'): u_groups = u.getGroupsInContext(ob) elif hasattr(b, 'getGroups'): u_groups = u.getGroups() else: u_groups = () for group in self.groups: if group in u_groups: break else: return 0 expr = self.expr if expr is not None: econtext = createExprContext(StateChangeInfo(ob, wf_def, kwargs=kw)) res = expr(econtext) if not res: return 0 return 1 security.declareProtected(ManagePortal, 'getSummary') def getSummary(self): # Perhaps ought to be in DTML. res = [] if self.permissions: res.append('Requires permission:') res.append(formatNameUnion(self.permissions)) if self.roles: if res: res.append('<br/>') res.append('Requires role:') res.append(formatNameUnion(self.roles)) if self.groups: if res: res.append('<br/>') res.append('Requires group:') res.append(formatNameUnion(self.groups)) if self.expr is not None: if res: res.append('<br/>') res.append('Requires expr:') res.append('<code>' + escape(self.expr.text) + '</code>') return ' '.join(res) def changeFromProperties(self, props): ''' Returns 1 if changes were specified. ''' if props is None: return 0 res = 0 s = props.get('guard_permissions', None) if s: res = 1 p = [permission.strip() for permission in s.split(';')] self.permissions = tuple(p) s = props.get('guard_roles', None) if s: res = 1 r = [role.strip() for role in s.split(';')] self.roles = tuple(r) s = props.get('guard_groups', None) if s: res = 1 g = [group.strip() for group in s.split(';')] self.groups = tuple(g) s = props.get('guard_expr', None) if s: res = 1 self.expr = Expression(s) return res security.declareProtected(ManagePortal, 'getPermissionsText') def getPermissionsText(self): if not self.permissions: return '' return '; '.join(self.permissions) security.declareProtected(ManagePortal, 'getRolesText') def getRolesText(self): if not self.roles: return '' return '; '.join(self.roles) security.declareProtected(ManagePortal, 'getGroupsText') def getGroupsText(self): if not self.groups: return '' return '; '.join(self.groups) security.declareProtected(ManagePortal, 'getExprText') def getExprText(self): if not self.expr: return '' return str(self.expr.text)
class DiscussionTool(UniqueObject, SimpleItem, ActionProviderBase): """ Links content to discussions. """ implements(IDiscussionTool) __implements__ = (z2IDiscussionTool, ActionProviderBase.__implements__) id = 'portal_discussion' meta_type = 'Default Discussion Tool' security = ClassSecurityInfo() manage_options = (ActionProviderBase.manage_options + ({ 'label': 'Overview', 'action': 'manage_overview' }, ) + SimpleItem.manage_options) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLResource('dtml/explainDiscussionTool', globals()) # # 'portal_discussion' interface methods # security.declarePublic('overrideDiscussionFor') def overrideDiscussionFor(self, content, allowDiscussion): """ Override discussability for the given object or clear the setting. """ mtool = getToolByName(self, 'portal_membership') if not mtool.checkPermission(ModifyPortalContent, content): raise AccessControl_Unauthorized if allowDiscussion is None or allowDiscussion == 'None': if hasattr(aq_base(content), 'allow_discussion'): del content.allow_discussion else: content.allow_discussion = bool(allowDiscussion) security.declarePublic('getDiscussionFor') def getDiscussionFor(self, content): """ Get DiscussionItemContainer for content, create it if necessary. """ if not self.isDiscussionAllowedFor(content): raise DiscussionNotAllowed if not IDiscussionResponse.providedBy(content) and \ not z2IDiscussionResponse.isImplementedBy(content) and \ getattr( aq_base(content), 'talkback', None ) is None: # Discussion Items use the DiscussionItemContainer object of the # related content item, so only create one for other content items self._createDiscussionFor(content) return content.talkback # Return wrapped talkback security.declarePublic('isDiscussionAllowedFor') def isDiscussionAllowedFor(self, content): """ Get boolean indicating whether discussion is allowed for content. """ if hasattr(content, 'allow_discussion'): return bool(content.allow_discussion) typeInfo = getToolByName(self, 'portal_types').getTypeInfo(content) if typeInfo: return bool(typeInfo.allowDiscussion()) return False # # Utility methods # security.declarePrivate('_createDiscussionFor') def _createDiscussionFor(self, content): """ Create DiscussionItemContainer for content, if allowed. """ if not self.isDiscussionAllowedFor(content): raise DiscussionNotAllowed content.talkback = DiscussionItemContainer() return content.talkback
class MetadataTool(UniqueObject, SimpleItem, ActionProviderBase): implements(IMetadataTool) __implements__ = (z2IMetadataTool, ActionProviderBase.__implements__) id = 'portal_metadata' meta_type = 'Default Metadata Tool' # # Default values. # publisher = '' element_specs = None #initial_values_hook = None #validation_hook = None security = ClassSecurityInfo() def __init__( self, publisher=None #, initial_values_hook=None #, validation_hook=None , element_specs=DEFAULT_ELEMENT_SPECS): self.editProperties(publisher #, initial_values_hook #, validation_hook ) self.element_specs = PersistentMapping() for name, is_multi_valued in element_specs: self.element_specs[name] = ElementSpec(is_multi_valued) # # ZMI methods # manage_options = ( ActionProviderBase.manage_options + ({ 'label': 'Overview', 'action': 'manage_overview' }, { 'label': 'Properties', 'action': 'propertiesForm' }, { 'label': 'Elements', 'action': 'elementPoliciesForm' } # TODO , { 'label' : 'Types' # , 'action' : 'typesForm' # } ) + SimpleItem.manage_options) security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLResource('dtml/explainMetadataTool', globals()) security.declareProtected(ManagePortal, 'propertiesForm') propertiesForm = DTMLResource('dtml/metadataProperties', globals()) security.declareProtected(ManagePortal, 'editProperties') def editProperties( self, publisher=None # TODO , initial_values_hook=None # TODO , validation_hook=None , REQUEST=None): """ Form handler for "tool-wide" properties (including list of metadata elements). """ if publisher is not None: self.publisher = publisher # TODO self.initial_values_hook = initial_values_hook # TODO self.validation_hook = validation_hook if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/propertiesForm' + '?manage_tabs_message=Tool+updated.') security.declareProtected(ManagePortal, 'elementPoliciesForm') elementPoliciesForm = DTMLResource('dtml/metadataElementPolicies', globals()) security.declareProtected(ManagePortal, 'addElementPolicy') def addElementPolicy(self, element, content_type, is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary, REQUEST=None): """ Add a type-specific policy for one of our elements. """ if content_type == '<default>': content_type = None spec = self.getElementSpec(element) spec.addPolicy(content_type) policy = spec.getPolicy(content_type) policy.edit(is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/elementPoliciesForm' + '?element=' + element + '&manage_tabs_message=Policy+added.') security.declareProtected(ManagePortal, 'removeElementPolicy') def removeElementPolicy(self, element, content_type, REQUEST=None): """ Remvoe a type-specific policy for one of our elements. """ if content_type == '<default>': content_type = None spec = self.getElementSpec(element) spec.removePolicy(content_type) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/elementPoliciesForm' + '?element=' + element + '&manage_tabs_message=Policy+removed.') security.declareProtected(ManagePortal, 'updateElementPolicy') def updateElementPolicy(self, element, content_type, is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary, REQUEST=None): """ Update a policy for one of our elements ('content_type' will be '<default>' when we edit the default). """ if content_type == '<default>': content_type = None spec = self.getElementSpec(element) policy = spec.getPolicy(content_type) policy.edit(is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/elementPoliciesForm' + '?element=' + element + '&manage_tabs_message=Policy+updated.') # # Element spec manipulation. # security.declareProtected(ManagePortal, 'listElementSpecs') def listElementSpecs(self): """ Return a list of ElementSpecs representing the elements managed by the tool. """ res = [] for k, v in self.element_specs.items(): res.append((k, v.__of__(self))) return res security.declareProtected(ManagePortal, 'getElementSpec') def getElementSpec(self, element): """ Return an ElementSpec representing the tool's knowledge of 'element'. """ return self.element_specs[element].__of__(self) security.declareProtected(ManagePortal, 'addElementSpec') def addElementSpec(self, element, is_multi_valued, REQUEST=None): """ Add 'element' to our list of managed elements. """ # Don't replace. if self.element_specs.has_key(element): return self.element_specs[element] = ElementSpec(is_multi_valued) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/propertiesForm' + '?manage_tabs_message=Element+' + element + '+added.') security.declareProtected(ManagePortal, 'removeElementSpec') def removeElementSpec(self, element, REQUEST=None): """ Remove 'element' from our list of managed elements. """ del self.element_specs[element] if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/propertiesForm' + '?manage_tabs_message=Element+' + element + '+removed.') security.declareProtected(ManagePortal, 'listPolicies') def listPolicies(self, typ=None): """ Show all policies for a given content type, or the default if None. """ result = [] for element, spec in self.listElementSpecs(): result.append((element, spec.getPolicy(typ))) return result # # 'portal_metadata' interface # security.declarePrivate('getFullName') def getFullName(self, userid): """ Convert an internal userid to a "formal" name, if possible, perhaps using the 'portal_membership' tool. Used to map userid's for Creator, Contributor DCMI queries. """ return userid # TODO: do lookup here security.declarePublic('getPublisher') def getPublisher(self): """ Return the "formal" name of the publisher of the portal. """ return self.publisher security.declarePublic('listAllowedVocabulary') def listAllowedVocabulary(self, element, content=None, content_type=None): """ List allowed keywords for a given portal_type, or all possible keywords if none supplied. """ spec = self.getElementSpec(element) if content_type is None and content: content_type = content.getPortalTypeName() return spec.getPolicy(content_type).allowedVocabulary() security.declarePublic('listAllowedSubjects') def listAllowedSubjects(self, content=None, content_type=None): """ List allowed keywords for a given portal_type, or all possible keywords if none supplied. """ return self.listAllowedVocabulary('Subject', content, content_type) security.declarePublic('listAllowedFormats') def listAllowedFormats(self, content=None, content_type=None): """ List the allowed 'Content-type' values for a particular portal_type, or all possible formats if none supplied. """ return self.listAllowedVocabulary('Format', content, content_type) security.declarePublic('listAllowedLanguages') def listAllowedLanguages(self, content=None, content_type=None): """ List the allowed language values. """ return self.listAllowedVocabulary('Language', content, content_type) security.declarePublic('listAllowedRights') def listAllowedRights(self, content=None, content_type=None): """ List the allowed values for a "Rights" selection list; this gets especially important where syndication is involved. """ return self.listAllowedVocabulary('Rights', content, content_type) security.declareProtected(ModifyPortalContent, 'setInitialMetadata') def setInitialMetadata(self, content): """ Set initial values for content metatdata, supplying any site-specific defaults. """ for element, policy in self.listPolicies(content.getPortalTypeName()): if not getattr(content, element)(): if policy.supplyDefault(): setter = getattr(content, 'set%s' % element) setter(policy.defaultValue()) elif policy.isRequired(): raise MetadataError, \ 'Metadata element %s is required.' % element # TODO: Call initial_values_hook, if present security.declareProtected(View, 'validateMetadata') def validateMetadata(self, content): """ Enforce portal-wide policies about DCI, e.g., requiring non-empty title/description, etc. Called by the CMF immediately before saving changes to the metadata of an object. """ for element, policy in self.listPolicies(content.getPortalTypeName()): value = getattr(content, element)() if not value and policy.isRequired(): raise MetadataError, \ 'Metadata element %s is required.' % element if value and policy.enforceVocabulary(): values = policy.isMultiValued() and value or [value] for value in values: if not value in policy.allowedVocabulary(): raise MetadataError, \ 'Value %s is not in allowed vocabulary for ' \ 'metadata element %s.' % ( value, element )
class MembershipTool(BaseTool): """ Implement 'portal_membership' interface using "stock" policies. """ implements(IMembershipTool) __implements__ = (z2IMembershipTool, ActionProviderBase.__implements__) meta_type = 'Default Membership Tool' membersfolder_id = 'Members' security = ClassSecurityInfo() # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLResource('dtml/explainMembershipTool', globals()) security.declareProtected(ManagePortal, 'manage_mapRoles') manage_mapRoles = DTMLResource('dtml/membershipRolemapping', globals()) security.declareProtected(ManagePortal, 'manage_setMembersFolderById') def manage_setMembersFolderById(self, id='', REQUEST=None): """ ZMI method to set the members folder object by its id. """ self.setMembersFolderById(id) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/manage_mapRoles' + '?manage_tabs_message=Members+folder+changed.') # # 'portal_membership' interface methods # security.declareProtected(ListPortalMembers, 'getRoster') def getRoster(self): """ Return a list of mappings for 'listed' members. If Manager, return a list of all usernames. The mapping contains the id and listed variables. """ isUserManager = _checkPermission(ManageUsers, self) roster = [] for member in self.listMembers(): if isUserManager or member.listed: roster.append({'id': member.getId(), 'listed': member.listed}) return roster security.declareProtected(ManagePortal, 'setMembersFolderById') def setMembersFolderById(self, id=''): """ Set the members folder object by its id. """ self.membersfolder_id = id.strip() security.declarePublic('getMembersFolder') def getMembersFolder(self): """ Get the members folder object. """ parent = aq_parent(aq_inner(self)) members = getattr(parent, self.membersfolder_id, None) return members security.declarePublic('createMemberArea') def createMemberArea(self, member_id=''): """ Create a member area for 'member_id' or authenticated user. """ if not self.getMemberareaCreationFlag(): return None members = self.getMembersFolder() if not members: return None if self.isAnonymousUser(): return None # Note: We can't use getAuthenticatedMember() and getMemberById() # because they might be wrapped by MemberDataTool. user = _getAuthenticatedUser(self) user_id = user.getId() if member_id in ('', user_id): member = user member_id = user_id else: if _checkPermission(ManageUsers, self): member = self.acl_users.getUserById(member_id, None) if member: member = member.__of__(self.acl_users) else: raise ValueError, 'Member %s does not exist' % member_id else: return None if hasattr(aq_base(members), member_id): return None # Note: We can't use invokeFactory() to add folder and content because # the user might not have the necessary permissions. # Create Member's home folder. members.manage_addPortalFolder(id=member_id, title="%s's Home" % member_id) f = members._getOb(member_id) # Grant Ownership and Owner role to Member f.changeOwnership(member) f.__ac_local_roles__ = None f.manage_setLocalRoles(member_id, ['Owner']) # Create Member's initial content. if hasattr(self, 'createMemberContent'): self.createMemberContent(member=member, member_id=member_id, member_folder=f) else: addDocument(f, 'index_html', member_id + "'s Home", member_id + "'s front page", "structured-text", (DEFAULT_MEMBER_CONTENT % member_id)) # Grant Ownership and Owner role to Member f.index_html.changeOwnership(member) f.index_html.__ac_local_roles__ = None f.index_html.manage_setLocalRoles(member_id, ['Owner']) f.index_html._setPortalTypeName('Document') f.index_html.reindexObject() f.index_html.notifyWorkflowCreated() return f security.declarePublic('createMemberarea') createMemberarea = createMemberArea def getHomeFolder(self, id=None, verifyPermission=0): """ Return a member's home folder object, or None. """ if id is None: member = self.getAuthenticatedMember() if not hasattr(member, 'getMemberId'): return None id = member.getMemberId() members = self.getMembersFolder() if members: try: folder = members._getOb(id) if verifyPermission and not _checkPermission(View, folder): # Don't return the folder if the user can't get to it. return None return folder except (AttributeError, TypeError, KeyError): pass return None def getHomeUrl(self, id=None, verifyPermission=0): """ Return the URL to a member's home folder, or None. """ home = self.getHomeFolder(id, verifyPermission) if home is not None: return home.absolute_url() else: return None
class VariableDefinition(SimpleItem): """Variable definition""" meta_type = 'Workflow Variable' security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) description = '' for_catalog = 1 for_status = 1 default_value = '' default_expr = None # Overrides default_value if set info_guard = None update_always = 1 manage_options = ( {'label': 'Properties', 'action': 'manage_properties'}, ) def __init__(self, id): self.id = id def getDefaultExprText(self): if not self.default_expr: return '' else: return self.default_expr.text def getInfoGuard(self): if self.info_guard is not None: return self.info_guard else: return Guard().__of__(self) # Create a temporary guard. def getInfoGuardSummary(self): res = None if self.info_guard is not None: res = self.info_guard.getSummary() return res _properties_form = DTMLResource('dtml/variable_properties', globals()) def manage_properties(self, REQUEST, manage_tabs_message=None): ''' ''' return self._properties_form(REQUEST, management_view='Properties', manage_tabs_message=manage_tabs_message, ) def setProperties(self, description, default_value='', default_expr='', for_catalog=0, for_status=0, update_always=0, props=None, REQUEST=None): ''' ''' self.description = str(description) self.default_value = str(default_value) if default_expr: self.default_expr = Expression(default_expr) else: self.default_expr = None g = Guard() if g.changeFromProperties(props or REQUEST): self.info_guard = g else: self.info_guard = None self.for_catalog = bool(for_catalog) self.for_status = bool(for_status) self.update_always = bool(update_always) if REQUEST is not None: return self.manage_properties(REQUEST, 'Properties changed.')
class SyndicationTool(UniqueObject, SimpleItem, ActionProviderBase): """ The syndication tool manages the site-wide policy for syndication of folder content as RSS. """ __implements__ = ActionProviderBase.__implements__ id = 'portal_syndication' meta_type = 'Default Syndication Tool' security = ClassSecurityInfo() #Default Sitewide Values isAllowed = 0 syUpdatePeriod = 'daily' syUpdateFrequency = 1 syUpdateBase = DateTime() max_items = 15 #ZMI Methods manage_options = ( ActionProviderBase.manage_options + ({ 'label': 'Overview', 'action': 'overview', 'help': ('CMFDefault', 'Syndication-Tool_Overview.stx') }, { 'label': 'Properties', 'action': 'propertiesForm', 'help': ('CMFDefault', 'Syndication-Tool_Properties.stx') }, { 'label': 'Policies', 'action': 'policiesForm', 'help': ('CMFDefault', 'Syndication-Tool_Policies.stx') }, { 'label': 'Reports', 'action': 'reportForm', 'help': ('CMFDefault', 'Syndication-Tool_Reporting.stx') })) security.declareProtected(ManagePortal, 'overview') overview = DTMLResource('dtml/synOverview', globals()) security.declareProtected(ManagePortal, 'propertiesForm') propertiesForm = DTMLResource('dtml/synProps', globals()) security.declareProtected(ManagePortal, 'policiesForm') policiesForm = DTMLResource('dtml/synPolicies', globals()) security.declareProtected(ManagePortal, 'reportForm') reportForm = DTMLResource('dtml/synReports', globals()) security.declareProtected(ManagePortal, 'editProperties') def editProperties(self, updatePeriod=None, updateFrequency=None, updateBase=None, isAllowed=None, max_items=None, REQUEST=None): """ Edit the properties for the SystemWide defaults on the SyndicationTool. """ if isAllowed is not None: self.isAllowed = isAllowed if updatePeriod is not None: self.syUpdatePeriod = updatePeriod else: try: del self.syUpdatePeriod except (AttributeError, KeyError): pass if updateFrequency is not None: self.syUpdateFrequency = int(updateFrequency) else: try: del self.syUpdateFrequency except (AttributeError, KeyError): pass if updateBase is not None: if type(updateBase) is type(''): updateBase = DateTime(updateBase) self.syUpdateBase = updateBase else: try: del self.syUpdateBase except (AttributeError, KeyError): pass if max_items is not None: self.max_items = int(max_items) else: try: del self.max_items except (AttributeError, KeyError): pass if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/propertiesForm' + '?manage_tabs_message=Tool+Updated.') security.declarePublic('editSyInformationProperties') def editSyInformationProperties(self, obj, updatePeriod=None, updateFrequency=None, updateBase=None, max_items=None, REQUEST=None): """ Edit syndication properties for the obj being passed in. These are held on the syndication_information object. Not Sitewide Properties. """ if not _checkPermission(ManageProperties, obj): raise AccessControl_Unauthorized syInfo = getattr(obj, 'syndication_information', None) if syInfo is None: raise 'Syndication is Disabled' if updatePeriod is not None: syInfo.syUpdatePeriod = updatePeriod else: syInfo.syUpdatePeriod = self.syUpdatePeriod if updateFrequency is not None: syInfo.syUpdateFrequency = int(updateFrequency) else: syInfo.syUpdateFrequency = self.syUpdateFrequency if updateBase is not None: if type(updateBase) is type(''): updateBase = DateTime(updateBase) syInfo.syUpdateBase = updateBase else: syInfo.syUpdateBase = self.syUpdateBase if max_items is not None: syInfo.max_items = int(max_items) else: syInfo.max_items = self.max_items security.declarePublic('enableSyndication') def enableSyndication(self, obj): """ Enable syndication for the obj """ if not self.isSiteSyndicationAllowed(): raise 'Syndication is Disabled' if hasattr(aq_base(obj), 'syndication_information'): raise 'Syndication Information Exists' syInfo = SyndicationInformation() obj._setObject('syndication_information', syInfo) syInfo = obj._getOb('syndication_information') syInfo.syUpdatePeriod = self.syUpdatePeriod syInfo.syUpdateFrequency = self.syUpdateFrequency syInfo.syUpdateBase = self.syUpdateBase syInfo.max_items = self.max_items syInfo.description = "Channel Description" security.declarePublic('disableSyndication') def disableSyndication(self, obj): """ Disable syndication for the obj; and remove it. """ syInfo = getattr(obj, 'syndication_information', None) if syInfo is None: raise 'This object does not have Syndication Information' obj._delObject('syndication_information') security.declarePublic('getSyndicatableContent') def getSyndicatableContent(self, obj): """ An interface for allowing folderish items to implement an equivalent of PortalFolderBase.contentValues() """ if hasattr(obj, 'synContentValues'): values = obj.synContentValues() else: values = PortalFolderBase.contentValues(obj) return values security.declarePublic('buildUpdatePeriods') def buildUpdatePeriods(self): """ Return a list of possible update periods for the xmlns: sy """ updatePeriods = (('hourly', 'Hourly'), ('daily', 'Daily'), ('weekly', 'Weekly'), ('monthly', 'Monthly'), ('yearly', 'Yearly')) return updatePeriods security.declarePublic('isSiteSyndicationAllowed') def isSiteSyndicationAllowed(self): """ Return sitewide syndication policy """ return self.isAllowed security.declarePublic('isSyndicationAllowed') def isSyndicationAllowed(self, obj=None): """ Check whether syndication is enabled for the site. This provides for extending the method to check for whether a particular obj is enabled, allowing for turning on only specific folders for syndication. """ syInfo = getattr(aq_base(obj), 'syndication_information', None) if syInfo is None: return 0 else: return self.isSiteSyndicationAllowed() security.declarePublic('getUpdatePeriod') def getUpdatePeriod(self, obj=None): """ Return the update period for the RSS syn namespace. This is either on the object being passed or the portal_syndication tool (if a sitewide value or default is set) NOTE: Need to add checks for sitewide policies!!! """ if not self.isSiteSyndicationAllowed(): raise 'Syndication is Not Allowed' if obj is None: return self.syUpdatePeriod syInfo = getattr(obj, 'syndication_information', None) if syInfo is not None: return syInfo.syUpdatePeriod else: return 'Syndication is Not Allowed' security.declarePublic('getUpdateFrequency') def getUpdateFrequency(self, obj=None): """ Return the update frequency (as a positive integer) for the syn namespace. This is either on the object being pass or the portal_syndication tool (if a sitewide value or default is set). Note: Need to add checks for sitewide policies!!! """ if not self.isSiteSyndicationAllowed(): raise 'Syndication is not Allowed' if obj is None: return self.syUpdateFrequency syInfo = getattr(obj, 'syndication_information', None) if syInfo is not None: return syInfo.syUpdateFrequency else: return 'Syndication is not Allowed' security.declarePublic('getUpdateBase') def getUpdateBase(self, obj=None): """ Return the base date to be used with the update frequency and the update period to calculate a publishing schedule. Note: I'm not sure what's best here, creation date, last modified date (of the folder being syndicated) or some arbitrary date. For now, I'm going to build a updateBase time from zopetime and reformat it to meet the W3CDTF. Additionally, sitewide policy checks might have a place here... """ if not self.isSiteSyndicationAllowed(): raise 'Syndication is not Allowed' if obj is None: when = self.syUpdateBase return when.ISO() syInfo = getattr(obj, 'syndication_information', None) if syInfo is not None: when = syInfo.syUpdateBase return when.ISO() else: return 'Syndication is not Allowed' security.declarePublic('getHTML4UpdateBase') def getHTML4UpdateBase(self, obj): """ Return HTML4 formated UpdateBase DateTime """ if not self.isSiteSyndicationAllowed(): raise 'Syndication is not Allowed' if obj is None: when = syUpdateBase return when.HTML4() syInfo = getattr(obj, 'syndication_information', None) if syInfo is not None: when = syInfo.syUpdateBase return when.HTML4() else: return 'Syndication is not Allowed' def getMaxItems(self, obj=None): """ Return the max_items to be displayed in the syndication """ if not self.isSiteSyndicationAllowed(): raise 'Syndication is not Allowed' if obj is None: return self.max_items syInfo = getattr(obj, 'syndication_information', None) if syInfo is not None: return syInfo.max_items else: return 'Syndication is not Allowed'
class WorklistDefinition(SimpleItem): """Worklist definiton""" meta_type = 'Worklist' security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) description = '' var_matches = None # Compared with catalog when set. actbox_name = '' actbox_url = '' actbox_category = 'global' guard = None manage_options = ({'label': 'Properties', 'action': 'manage_properties'}, ) def __init__(self, id): self.id = id def getGuard(self): if self.guard is not None: return self.guard else: return Guard().__of__(self) # Create a temporary guard. def getGuardSummary(self): res = None if self.guard is not None: res = self.guard.getSummary() return res def getWorkflow(self): return aq_parent(aq_inner(aq_parent(aq_inner(self)))) def getAvailableCatalogVars(self): res = [] res.append(self.getWorkflow().state_var) for id, vdef in self.getWorkflow().variables.items(): if vdef.for_catalog: res.append(id) res.sort() return res def getVarMatchKeys(self): if self.var_matches: return self.var_matches.keys() else: return [] def getVarMatch(self, id): if self.var_matches: matches = self.var_matches.get(id, ()) if not isinstance(matches, tuple): # Old version, convert it. matches = (matches, ) self.var_matches[id] = matches return matches else: return () def getVarMatchText(self, id): values = self.getVarMatch(id) return '; '.join(values) _properties_form = DTMLResource('dtml/worklist_properties', globals()) def manage_properties(self, REQUEST, manage_tabs_message=None): ''' ''' return self._properties_form( REQUEST, management_view='Properties', manage_tabs_message=manage_tabs_message, ) def setProperties(self, description, actbox_name='', actbox_url='', actbox_category='global', props=None, REQUEST=None): ''' ''' if props is None: props = REQUEST self.description = str(description) for key in self.getAvailableCatalogVars(): # Populate var_matches. fieldname = 'var_match_%s' % key v = props.get(fieldname, '') if v: if not self.var_matches: self.var_matches = PersistentMapping() v = [var.strip() for var in v.split(';')] self.var_matches[key] = tuple(v) else: if self.var_matches and self.var_matches.has_key(key): del self.var_matches[key] self.actbox_name = str(actbox_name) self.actbox_url = str(actbox_url) self.actbox_category = str(actbox_category) g = Guard() if g.changeFromProperties(props or REQUEST): self.guard = g else: self.guard = None if REQUEST is not None: return self.manage_properties(REQUEST, 'Properties changed.')
class Document(PortalContent, DefaultDublinCoreImpl): """A Document - Handles both StructuredText and HTML. """ implements(IDocument, IMutableDocument) __implements__ = (z2IDocument, z2IMutableDocument, PortalContent.__implements__, DefaultDublinCoreImpl.__implements__) meta_type = 'Document' effective_date = expiration_date = None cooked_text = text = text_format = '' _size = 0 _isDiscussable = 1 _stx_level = 1 # Structured text level _last_safety_belt_editor = '' _last_safety_belt = '' _safety_belt = '' security = ClassSecurityInfo() def __init__(self, id, title='', description='', text_format='', text=''): DefaultDublinCoreImpl.__init__(self) self.id = id self.title = title self.description = description self._edit(text=text, text_format=text_format) self.setFormat(text_format) security.declareProtected(ModifyPortalContent, 'manage_edit') manage_edit = DTMLResource('dtml/zmi_editDocument', globals()) security.declareProtected(ModifyPortalContent, 'manage_editDocument') def manage_editDocument(self, text, text_format, file='', REQUEST=None): """ A ZMI (Zope Management Interface) level editing method """ Document.edit(self, text_format=text_format, text=text, file=file) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/manage_edit' + '?manage_tabs_message=Document+updated') def _edit(self, text, text_format='', safety_belt=''): """ Edit the Document and cook the body. """ if not self._safety_belt_update(safety_belt=safety_belt): msg = ("Intervening changes from elsewhere detected." " Please refetch the document and reapply your changes." " (You may be able to recover your version using the" " browser 'back' button, but will have to apply them" " to a freshly fetched copy.)") raise EditingConflict(msg) self.text = text self._size = len(text) if not text_format: text_format = self.text_format if text_format == 'html': self.cooked_text = text elif text_format == 'plain': self.cooked_text = html_quote(text).replace('\n', '<br />') else: self.cooked_text = HTML(text, level=self._stx_level, header=0) # # IMutableDocument method # security.declareProtected(ModifyPortalContent, 'edit') def edit(self, text_format, text, file='', safety_belt=''): """ Update the document. To add webDav support, we need to check if the content is locked, and if so return ResourceLockedError if not, call _edit. Note that this method expects to be called from a web form, and so disables header processing """ self.failIfLocked() if file and (type(file) is not type('')): contents = file.read() if contents: text = contents if html_headcheck(text) and text_format.lower() != 'plain': text = bodyfinder(text) self.setFormat(text_format) self._edit(text=text, text_format=text_format, safety_belt=safety_belt) self.reindexObject() security.declareProtected(ModifyPortalContent, 'setMetadata') def setMetadata(self, headers): headers['Format'] = self.Format() new_subject = keywordsplitter(headers) headers['Subject'] = new_subject or self.Subject() new_contrib = contributorsplitter(headers) headers['Contributors'] = new_contrib or self.Contributors() haveheader = headers.has_key for key, value in self.getMetadataHeaders(): if not haveheader(key): headers[key] = value self._editMetadata( title=headers['Title'], subject=headers['Subject'], description=headers['Description'], contributors=headers['Contributors'], effective_date=headers['Effective_date'], expiration_date=headers['Expiration_date'], format=headers['Format'], language=headers['Language'], rights=headers['Rights'], ) security.declarePrivate('guessFormat') def guessFormat(self, text): """ Simple stab at guessing the inner format of the text """ if html_headcheck(text): return 'html' else: return 'structured-text' security.declarePrivate('handleText') def handleText(self, text, format=None, stx_level=None): """ Handles the raw text, returning headers, body, format """ headers = {} if not format: format = self.guessFormat(text) if format == 'html': parser = SimpleHTMLParser() parser.feed(text) headers.update(parser.metatags) if parser.title: headers['Title'] = parser.title body = bodyfinder(text) else: headers, body = parseHeadersBody(text, headers) if stx_level: self._stx_level = stx_level return headers, body, format security.declarePublic('getMetadataHeaders') def getMetadataHeaders(self): """Return RFC-822-style header spec.""" hdrlist = DefaultDublinCoreImpl.getMetadataHeaders(self) hdrlist.append(('SafetyBelt', self._safety_belt)) return hdrlist security.declarePublic('SafetyBelt') def SafetyBelt(self): """Return the current safety belt setting. For web form hidden button.""" return self._safety_belt def _safety_belt_update(self, safety_belt=''): """Check validity of safety belt and update tracking if valid. Return 0 if safety belt is invalid, 1 otherwise. Note that the policy is deliberately lax if no safety belt value is present - "you're on your own if you don't use your safety belt". When present, either the safety belt token: - ... is the same as the current one given out, or - ... is the same as the last one given out, and the person doing the edit is the same as the last editor.""" this_belt = safety_belt this_user = getSecurityManager().getUser().getId() if ( # we have a safety belt value: this_belt # and the current object has a safety belt (ie - not freshly made) and (self._safety_belt is not None) # and the safety belt doesn't match the current one: and (this_belt != self._safety_belt) # and safety belt and user don't match last safety belt and user: and not ((this_belt == self._last_safety_belt) and (this_user == self._last_safety_belt_editor))): # Fail. return 0 # We qualified - either: # - the edit was submitted with safety belt stripped, or # - the current safety belt was used, or # - the last one was reused by the last person who did the last edit. # In any case, update the tracking. self._last_safety_belt_editor = this_user self._last_safety_belt = this_belt self._safety_belt = str(self._p_mtime) return 1 ### Content accessor methods # # IContentish method # security.declareProtected(View, 'SearchableText') def SearchableText(self): """ Used by the catalog for basic full text indexing """ return "%s %s %s" % (self.Title(), self.Description(), self.EditableBody()) # # IDocument methods # security.declareProtected(View, 'CookedBody') def CookedBody(self, stx_level=None, setlevel=0): """ Get the "cooked" (ready for presentation) form of the text. The prepared basic rendering of an object. For Documents, this means pre-rendered structured text, or what was between the <BODY> tags of HTML. If the format is html, and 'stx_level' is not passed in or is the same as the object's current settings, return the cached cooked text. Otherwise, recook. If we recook and 'setlevel' is true, then set the recooked text and stx_level on the object. """ if (self.text_format == 'html' or self.text_format == 'plain' or (stx_level is None) or (stx_level == self._stx_level)): return self.cooked_text else: cooked = HTML(self.text, level=stx_level, header=0) if setlevel: self._stx_level = stx_level self.cooked_text = cooked return cooked security.declareProtected(View, 'EditableBody') def EditableBody(self): """ Get the "raw" (as edited) form of the text. The editable body of text. This is the raw structured text, or in the case of HTML, what was between the <BODY> tags. """ return self.text # # IDublinCore method # security.declareProtected(View, 'Format') def Format(self): """ Dublin Core Format element - resource format. """ if self.text_format == 'html': return 'text/html' else: return 'text/plain' # # IMutableDublinCore method # security.declareProtected(ModifyPortalContent, 'setFormat') def setFormat(self, format): """ Set text format and Dublin Core resource format. """ value = str(format) old_value = self.text_format if value == 'text/html' or value == 'html': self.text_format = 'html' elif value == 'text/plain': if self.text_format not in ('structured-text', 'plain'): self.text_format = 'structured-text' elif value == 'plain': self.text_format = 'plain' else: self.text_format = 'structured-text' # Did the format change? We might need to re-cook the content. if value != old_value: if html_headcheck(self.text) and value != 'plain': self.text = bodyfinder(self.text) self._edit(self.text, text_format=self.text_format, safety_belt=self._safety_belt) ## FTP handlers security.declareProtected(ModifyPortalContent, 'PUT') def PUT(self, REQUEST, RESPONSE): """ Handle HTTP (and presumably FTP?) PUT requests """ self.dav__init(REQUEST, RESPONSE) self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1) body = REQUEST.get('BODY', '') headers, body, format = self.handleText(text=body) safety_belt = headers.get('SafetyBelt', '') if REQUEST.get_header('Content-Type', '') == 'text/html': text_format = 'html' else: text_format = format try: self.setFormat(text_format) self.setMetadata(headers) self._edit(text=body, safety_belt=safety_belt) except EditingConflict, msg: # XXX Can we get an error msg through? Should we be raising an # exception, to be handled in the FTP mechanism? Inquiring # minds... transaction.abort() RESPONSE.setStatus(450) return RESPONSE except ResourceLockedError, msg: transaction.abort() RESPONSE.setStatus(423) return RESPONSE