class Folder(Site): """Enable, disable and customise syndication settings for a folder. """ label = _(u"Configure Folder Syndication") actions = form.Actions(*Site.actions.actions) actions.append( form.Action( name="revert", label=_(u"Revert to Site Default"), condition="enabled", success="handle_revert", ) ) redirect = ("portal_actions", "object/syndication") @memoize def getContent(self): return getAdapter(self.context, ISyndicationInfo) @memoize def allowed(self, action=None): return self.getContent().allowed def handle_revert(self, action, data): self.getContent().revert() self.status = _(u"Syndication reset to site default.") self._setRedirect(*self.redirect)
class Submit(EditFormBase): """Submit an item for review""" template = ViewPageTemplateFile("submit.pt") form_fields = form.FormFields(IWorkflowSchema) actions = form.Actions( form.Action(name="submit", label=_(u"Submit item"), success='handle_workflow', failure='handle_failure')) @property @memoize def workflow(self): return getUtility(IWorkflowTool) def handle_workflow(self, action, data): try: self.workflow.doActionFor(self.context, action.name, comment=data['comment']) self.status = STATUS.get(action.name, _(u"Status changed.")) self._setRedirect('portal_types', 'object/view') except WorkflowException, errmsg: self.status = errmsg self._setRedirect('portal_actions', 'object/edit')
class DisplayViewlet(BungeniAttributeDisplay): """Display a target object; if the object is `None`, the user is prompted to add it. """ mode = "view" for_display = True query = None factory = None has_data = False form_fields = form.Fields() add_action = form.Actions(form.Action(_(u"Add"), success="handle_add"), ) def __init__(self, context, request, view, manager): super(DisplayViewlet, self).__init__(context, request, view, manager) # set add url before we change context self.add_url = self.get_add_url() target = self.get_target() if target is None: self.status = _(u"No item has been set") else: self.context = target self.has_data = True assert self.factory is not None descriptor = queryModelDescriptor(self.factory) self.form_fields = descriptor.fields def update(self): # only if there's data to display do we update using our # immediate superclass if self.has_data: super(DisplayViewlet, self).update() else: self.setupActions() super(form.SubPageDisplayForm, self).update() def handle_add(self, action, data): self.request.response.redirect(self.add_url) def get_add_url(self): raise NotImplementedError("Must be implemented by subclass.") def get_target(self): raise NotImplementedError("Must be implemented by subclass.") def set_target(self, target): raise NotImplementedError("Must be implemented by subclass.") def setupActions(self): if self.has_data: super(DisplayViewlet, self).setupActions() else: self.actions = self.add_action.actions @property def form_name(self): descriptor = queryModelDescriptor(self.factory) return descriptor.display_name
class ContentEditFormBase(_EditFormMixin, PageForm): actions = form.Actions( form.Action( name='change', label=_(u'Change'), validator='handle_validate', success='handle_change_success', failure='handle_failure'), form.Action( name='change_and_view', label=_(u'Change and View'), validator='handle_validate', success='handle_change_and_view_success', failure='handle_failure')) description = u'' def setUpWidgets(self, ignore_request=False): self.adapters = {} self.widgets = form.setUpEditWidgets( self.form_fields, self.prefix, self.context, self.request, adapters=self.adapters, ignore_request=ignore_request ) @property def label(self): obj_type = translate(self.context.Type(), self.context) return _(u'Edit ${obj_type}', mapping={'obj_type': obj_type}) def handle_validate(self, action, data): if self.context.wl_isLocked(): return (_(u'This resource is locked via webDAV.'),) return None def _handle_success(self, action, data): # normalize set and datetime for k, v in data.iteritems(): if isinstance(v, Set): data[k] = set(v) elif isinstance(v, datetime) and v.tzname() is None: data[k] = parseDatetimetz(str(v)) changed = form.applyChanges(self.context, self.form_fields, data, self.adapters) if changed: self.context.reindexObject() obj_type = translate(self.context.Type(), self.context) self.status = _(u'${obj_type} changed.', mapping={'obj_type': obj_type}) else: self.status = _(u'Nothing to change.') return changed def handle_change_success(self, action, data): self._handle_success(action, data) return self._setRedirect('portal_types', 'object/edit') def handle_change_and_view_success(self, action, data): self._handle_success(action, data) return self._setRedirect('portal_types', 'object/view')
class Site(SettingsEditFormBase): """Enable or disable syndication for a site.""" form_fields = form.FormFields(ISyndicationInfo).omit('enabled') label = _(u"Configure Portal Syndication") actions = form.Actions( form.Action( name="enable", label=_(u"Enable Syndication"), condition="disabled", success="handle_enable", ), form.Action( name="change", label=_(u"Change"), condition="enabled", success="handle_change", ), form.Action( name="disable", label=_(u"Disable Syndication"), condition="enabled", success="handle_disable" ) ) redirect = ("portal_actions", "global/syndication") @memoize def getContent(self): syndtool = getUtility(ISyndicationTool) return syndtool @memoize def enabled(self, action=None): return self.getContent().enabled @memoize def disabled(self, action=None): return not self.getContent().enabled def handle_enable(self, action, data): self.getContent().enable() self._handle_success(action, data) self.status = _(u"Syndication enabled.") self._setRedirect(*self.redirect) def handle_change(self, action, data): self._handle_success(action, data) self.status = _(u"Syndication settings changed.") self._setRedirect(*self.redirect) def handle_disable(self, action, data): self.getContent().disable() self.status = _(u"Syndication disabled.") self._setRedirect(*self.redirect)
class Hide(Submit): """Hide a published item""" template = ViewPageTemplateFile("hide.pt") form_fields = form.FormFields(IWorkflowSchema) actions = form.Actions( form.Action(name="hide", label=_(u"Hide this item"), success='handle_workflow', failure='handle_failure'))
class Show(Submit): """Reveal a hidden item""" template = ViewPageTemplateFile("show.pt") form_fields = form.FormFields(IWorkflowSchema) actions = form.Actions( form.Action(name="show", label=_(u"Show this item"), success='handle_workflow', failure='handle_failure'))
class Publish(Submit): """Publish an item""" template = ViewPageTemplateFile("publish.pt") form_fields = form.FormFields(IWorkflowSchema) actions = form.Actions( form.Action(name="publish", label=_(u"Publish this item"), success='handle_workflow', failure='handle_failure'))
class Reject(Submit): """Reject an item submitted for publication""" template = ViewPageTemplateFile("reject.pt") form_fields = form.FormFields(IWorkflowSchema) actions = form.Actions( form.Action(name="reject", label=_(u"Reject this item"), success='handle_workflow', failure='handle_failure'))
class Retract(Submit): """Remove a published object""" template = ViewPageTemplateFile("retract.pt") form_fields = form.FormFields(IWorkflowSchema) actions = form.Actions( form.Action(name="retract", label=_(u"Retract this item"), success='handle_workflow', failure='handle_failure'))
class AllItems(OrderContentsComponent): actions = form.Actions() columns = list(OrderContentsComponent.columns) columns.remove(OrderContentsComponent.selection_column) def update(self): self.line_items = self.__parent__.context.shopping_cart.values() return super(OrderContentsComponent, self).update()
class Discuss(EditFormBase): """ Discuss an item """ form_fields = form.FormFields(IDiscussion) actions = form.Actions( form.Action( name="add", label=_("Add"), condition=1, validator="validate", success="handle_add" ), form.Action( name="edit", label=_("Edit"), condition=1, success="handle_edit", ), form.Action( name="preview", label=_("Preview"), condition=1, success="handle_preview", ) ) redirect = ("portal_actions", "object/view") @property @memoize def dtool(self): return getUtility(IDiscussionTool) @property def is_preview(self): pass def handle_add(self, action, data): """Create comment and redirect to it""" talkback = self.dtool.getDiscussionFor(self.context) replyID = talkback.createReply(title=data['title'], text=data['text']) reply = talkback.getReply(replyID) self.status = _(u"Reply added.") self.context.setRedirect(reply, "object/view") def handle_preview(self, action, data): """Preview comment and allow editing or adding""" pass def handle_edit(self, action, data): """Edit comment before submitting it""" pass
class LoginFormView(EditFormBase): """Form view for ILoginSchema. """ base_template = EditFormBase.template template = ViewPageTemplateFile('login.pt') label = _(u'Log in') prefix = '' form_fields = form.FormFields(ILoginSchema) actions = form.Actions( form.Action(name='login', label=_(u'Login'), validator='handle_login_validate', success='handle_login_success', failure='handle_failure')) def setUpWidgets(self, ignore_request=False): cctool = queryUtility(ICookieCrumbler) if cctool is not None: ac_name_id = cctool.name_cookie ac_password_id = cctool.pw_cookie ac_persistent_id = cctool.persist_cookie else: ac_name_id = '__ac_name' ac_password_id = '__ac_password' ac_persistent_id = '__ac_persistent' ac_name = self.request.get(ac_name_id) if ac_name is not None: self.request.form['name'] = ac_name self.request.form[ac_name_id] = ac_name ac_persistent = self.request.get(ac_persistent_id) if ac_persistent is not None: self.request.form['persistent'] = ac_persistent ac_persistent_used = self.request.get("%s.used" % ac_persistent_id) if ac_persistent_used is not None: self.request.form['persistent.used'] = ac_persistent_used super(LoginFormView, self).setUpWidgets(ignore_request=ignore_request) self.widgets['came_from'].hide = True self.widgets['name'].name = ac_name_id self.widgets['password'].name = ac_password_id self.widgets['persistent'].name = ac_persistent_id def handle_login_validate(self, action, data): mtool = getUtility(IMembershipTool) if mtool.isAnonymousUser(): _expireAuthCookie(self) return (_(u'Login failure'), ) return None def handle_login_success(self, action, data): return self._setRedirect('portal_actions', 'user/logged_in', 'came_from')
class MetadataEditView(ContentEditFormBase): """Edit view for IMutableDublinCore. """ actions = form.Actions( form.Action( name='change', label=_(u'Change'), validator='handle_validate', success='handle_change_success', failure='handle_failure'), form.Action( name='change_and_edit', label=_(u'Change and Edit'), validator='handle_validate', success='handle_change_and_edit_success', failure='handle_failure'), form.Action( name='change_and_view', label=_(u'Change and View'), validator='handle_validate', success='handle_change_and_view_success', failure='handle_failure')) form_fields = form.FormFields(IMetadataSchema) form_fields['subject'].custom_widget = SubjectInputWidget form_fields['contributors'].custom_widget = TupleInputWidget form_fields['effective'].custom_widget = DatetimeI18nWidget form_fields['expires'].custom_widget = DatetimeI18nWidget label = _(u'Properties') def setUpWidgets(self, ignore_request=False): super(MetadataEditView, self).setUpWidgets(ignore_request=ignore_request) self.widgets['allow_discussion']._messageNoValue = _(u'Default') self.widgets['description'].height = 4 self.widgets['subject'].split = True self.widgets['contributors'].height = 6 self.widgets['contributors'].split = True self.widgets['created'].split = True self.widgets['modified'].split = True self.widgets['effective'].split = True self.widgets['expires'].split = True def handle_change_success(self, action, data): self._handle_success(action, data) return self._setRedirect('portal_types', 'object/metadata') def handle_change_and_edit_success(self, action, data): self._handle_success(action, data) return self._setRedirect('portal_types', 'object/edit')
class GrokForm(object): """Mix-in to consolidate zope.formlib's forms with grok.View and to add some more useful methods. The consolidation needs to happen because zope.formlib's Forms have update/render methods which have different meanings than grok.View's update/render methods. We deal with this issue by 'renaming' zope.formlib's update() to update_form() and by disallowing subclasses to have custom render() methods.""" actions = form.Actions() def update(self): """Subclasses can override this method just like on regular grok.Views. It will be called before any form processing happens.""" def update_form(self): """Update the form, i.e. process form input using widgets. On zope.formlib forms, this is what the update() method is. In grok views, the update() method has a different meaning. That's why this method is called update_form() in grok forms.""" super(GrokForm, self).update() def render(self): """Render the form, either using the form template or whatever the actions returned in form_result.""" # if the form has been updated, it will already have a result if self.form_result is None: if self.form_reset: # we reset, in case data has changed in a way that # causes the widgets to have different data self.resetForm() self.form_reset = False self.form_result = self._render_template() return self.form_result # Mark the render() method as a method from the base class. That # way we can detect whether somebody overrides render() in a # subclass (which we don't allow). render.base_method = True def __call__(self): mapply(self.update, (), self.request) if self.request.response.getStatus() in (302, 303): # A redirect was triggered somewhere in update(). Don't # continue rendering the template or doing anything else. return self.update_form() return self.render()
class MailPasswordFormView(EditFormBase): """Form view for IMailPasswordSchema. """ template = ViewPageTemplateFile('mail_password.pt') label = _(u"Don't panic!") description = _(u"Just enter your member ID below, click 'Send', and " u"your password will be mailed to you if you gave a " u"valid email address when you signed on.") form_fields = form.FormFields(IMailPasswordSchema) form_fields['name'].custom_widget = TextWidget actions = form.Actions( form.Action(name='send', label=_(u'Send'), success='handle_send_success', failure='handle_failure')) def setUpWidgets(self, ignore_request=False): cctool = queryUtility(ICookieCrumbler) if cctool is not None: ac_name_id = cctool.name_cookie else: ac_name_id = '__ac_name' ac_name = self.request.get(ac_name_id) if ac_name and not ('%s.name' % self.prefix) in self.request: self.request.form['%s.name' % self.prefix] = ac_name super(MailPasswordFormView, self).setUpWidgets(ignore_request=ignore_request) def handle_send_success(self, action, data): mtool = getUtility(IMembershipTool) if not mtool.getMemberById(data['name']): candidates = mtool.searchMembers('email', data['name']) for candidate in candidates: if candidate['email'].lower() == data['name'].lower(): data['name'] = candidate['username'] break rtool = getUtility(IRegistrationTool) rtool.mailPassword(data['name'], self.request) self.status = _(u'Your password has been mailed to you.') return self._setRedirect('portal_actions', 'user/login') @property @memoize def admin_email(self): ptool = getUtility(IPropertiesTool) return ptool.getProperty('email_from_address')
class SettingsEditFormBase(_EditFormMixin, form.PageForm): """Base class for editing global settings. """ actions = form.Actions( form.Action(name='change', label=_(u'Change'), success='handle_change_success', failure='handle_failure'), form.Action(name='cancel', label=_(u'Cancel'), validator='handle_cancel_validate', success='handle_cancel_success')) description = u'' successMessage = _(u"Settings changed.") noChangesMessage = _(u'Nothing to change.') def getContent(self): return self.context def setUpWidgets(self, ignore_request=False): self.adapters = {} self.widgets = form.setUpEditWidgets(self.form_fields, self.prefix, self.getContent(), self.request, adapters=self.adapters, ignore_request=ignore_request) def applyChanges(self, data): return form.applyData(self.getContent(), self.form_fields, data, self.adapters) def _handle_success(self, action, data): # normalize set and datetime for k, v in data.iteritems(): if isinstance(v, Set): data[k] = set(v) elif isinstance(v, datetime) and v.tzinfo: # DatetimeWidget returns offset-aware datetime objects data[k] = v.replace(tzinfo=None) changes = self.applyChanges(data) if changes: self.status = self.successMessage else: self.status = self.noChangesMessage return changes
def __init__(self, *args): super(BaseForm, self).__init__(*args) if str(self.request.get("headless", "")).lower() in TRUE_VALS: self.setPrefix(NO_PREFIX) # in headless mode, the first action defined is submitted # by default for action in self.actions: default = DefaultAction(action) self.actions = form.Actions(default) break # the ``_next_url`` attribute is used internally by our # superclass to implement formlib's ``nextURL`` method next_url = self._next_url = self.request.get('next_url', None) if next_url == "...": self._next_url = self.request['HTTP_REFERER']
class PayableCreation(PayableForm): actions = form.Actions() def update(self): marker.mark(self.context, self.marker) # create a temporary object so we don't have to modify context until we're ready to activate # it.. this creates some odd behavior on remarking though, where the user is always filling # in new values even though previously values are present in the underlying contxt annotation. self.adapters = { self.interface: options.PropertyBag.makeinstance(self.interface), igetpaid.IPayable: options.PropertyBag.makeinstance(igetpaid.IPayable) } return super(PayableForm, self).update() @form.action(_("Activate"), condition=form.haveInputWidgets) def activate_payable(self, action, data): self.adapters = {} self.handle_edit_action.success_handler(self, action, data) try: adapter = self.adapters[ self.form_fields['made_payable_by'].interface] except AttributeError: # BBB for Zope 2.10 adapter = self.adapters[ self.form_fields['made_payable_by'].field.interface] adapter.made_payable_by = getSecurityManager().getUser().getId() notify( event.PayableCreationEvent(self.context, adapter, self.interface)) # redirect to view translated_message = self.context.utranslate( u'Changes saved.', domain='plone').encode(self.context.getCharset()) encoded_message = urlencode( {'portal_status_message': translated_message}) extra = view_url(self.context) self.request.response.redirect( '%s%s?%s' % (self.context.absolute_url(), extra, encoded_message))
class ContentEditFormBase(SettingsEditFormBase): actions = form.Actions( form.Action(name='change', label=_(u'Change'), validator='handle_validate', success='handle_change_success', failure='handle_failure'), form.Action(name='change_and_view', label=_(u'Change and View'), validator='handle_validate', success='handle_change_and_view_success', failure='handle_failure')) @property def label(self): obj_type = translate(self.context.Type(), self.context) return _(u'Edit ${obj_type}', mapping={'obj_type': obj_type}) @property def successMessage(self): obj_type = translate(self.context.Type(), self.context) return _(u'${obj_type} changed.', mapping={'obj_type': obj_type}) def handle_validate(self, action, data): if self.context.wl_isLocked(): return (_(u'This resource is locked via webDAV.'), ) return self.validate(action, data) def applyChanges(self, data): changes = super(ContentEditFormBase, self).applyChanges(data) # ``changes`` is a dictionary; if empty, there were no changes if changes: self.context.reindexObject() return changes def handle_change_success(self, action, data): self._handle_success(action, data) return self._setRedirect('portal_types', 'object/edit') def handle_change_and_view_success(self, action, data): self._handle_success(action, data) return self._setRedirect('portal_types', 'object/view')
class ResponseViewlet(BungeniAttributeDisplay): """Response to question.""" mode = "view" for_display = True form_name = _(u"Response") add_action = form.Actions( form.Action(_(u'Add response'), success='handle_response_add_action'), ) def __init__(self, context, request, view, manager): self.context = context self.request = request self.__parent__ = view self.manager = manager self.query = None md = queryModelDescriptor(domain.Response) self.form_fields = md.fields self.add_url = '%s/responses/add' % url.absoluteURL( self.context, self.request) def handle_response_add_action(self, action, data): self.request.response.redirect(self.add_url) def update(self): context = self.context responses = context.responses if len(responses): self.context = tuple(responses.values())[0] self.has_data = True else: self.context = domain.Response() self.has_data = False super(ResponseViewlet, self).update() def setupActions(self): if self.has_data: super(ResponseViewlet, self).setupActions() else: self.actions = self.add_action.actions
class Search(EditFormBase): """Portal Search Form""" template = ViewPageTemplateFile('search.pt') actions = form.Actions( form.Action( name='search', label=_(u"Search"), success='handle_search', failure='handle_failure', ), ) @property def label(self): return _(u'Search ${portal_title}', mapping={'portal_title': self.title()}) @property def form_fields(self): form_fields = form.FormFields(ISearchSchema) form_fields['review_state'].custom_widget = ChoiceMultiSelectWidget form_fields['Subject'].custom_widget = ChoiceMultiSelectWidget form_fields['portal_type'].custom_widget = ChoiceMultiSelectWidget if not self._checkPermission(ReviewPortalContent): form_fields = form_fields.omit('review_state') return form_fields def handle_search(self, action, data): if 'form.created' in self.request.form: del self.request.form['form.created'] if 'created' in data and data['created']: created = record() created.query = DateTime(str(data['created'])) created.range = 'min' self.request.form['form.created'] = created return self._setRedirect('portal_actions', 'global/search', 'review_state,SearchableText,Title,Subject,' 'Description,created,portal_type,' 'listCreators')
class TimeLineViewlet( viewlet.ViewletBase ): """ tracker/timeline view: Chronological changes are aggregated from : bill workflow, bill audit, bill scheduling and bill event records. """ sql_timeline = "" add_action = form.Actions( form.Action(_(u'add event'), success='handle_event_add_action'), ) for_display = True view_name = "Timeline" view_id ="unknown-timeline" # sqlalchemy give me a rough time sorting a union, with hand coded sql it is much easier. def __init__( self, context, request, view, manager ): self.context = context self.request = request self.__parent__= view self.manager = manager self.query = None def handle_event_add_action( self, action, data ): self.request.response.redirect(self.addurl) def update(self): """ refresh the query """ item_id = self.context.parliamentary_item_id self.results = queries.execute_sql( self.sql_timeline, item_id=item_id) path = ui_url.absoluteURL(self.context, self.request) self.addurl = '%s/event/add' %( path ) render = ViewPageTemplateFile ('templates/timeline_viewlet.pt')
class EnvironmentFormCreation(BaseEnvironmentForm): actions = form.Actions() def update(self): marker.mark(self.context, self.marker) self.adapters = { self.interface: options.PropertyBag.makeinstance(self.interface), self.interface: options.PropertyBag.makeinstance(self.interface) } return super(BaseEnvironmentForm, self).update() @button.buttonAndHandler(_('label_enable'), name='activate') def activateEnvironment(self, action): data, errors = self.extractData() changes = self.applyChanges(data) notify(zope.lifecycleevent.ObjectModifiedEvent(self.context)) notify( event.EnvironmentCreationEvent(self.context, self.adapters[self.interface], self.interface)) # redirect to view translated_message = self.context.utranslate( u'Changes saved.', domain='plone').encode('utf-8') encoded_message = urlencode( {'portal_status_message': translated_message}) extra = view_url(self.context) getToolByName(self.context, 'portal_css').cookResources() self.request.response.redirect( '%s%s?%s' % (self.context.absolute_url(), extra, encoded_message)) @button.buttonAndHandler(_('label_cancel'), name='cancel') def handleCancel(self, action): marker.erase(self.context, self.marker) self.request.RESPONSE.redirect(self.context.absolute_url())
class ElasticIndexSettings(ControlPanelForm): label = _("Elasticsearch configuration") description = _("Configure elasticsearch index.") form_name = _("Elasticsearch configuration") form_fields = form.Fields(IElasticSettings) @form.action('Create index', name='create_index') def create_index(self, action, data): send = IStatusMessage(self.request).add try: create_index(IElasticSettings(self.context)) except: send("Error while creating the index.", type='error') else: send("Index created.") @form.action('Delete index', name='delete_index') def delete_index(self, action, data): send = IStatusMessage(self.request).add try: delete_index(IElasticSettings(self.context)) except: send("Error while deleting the index.", type='error') else: send("Index deleted.") @form.action('Import site content', name='import_content') def import_site_content(self, action, data): send = IStatusMessage(self.request).add try: changes.verify_and_index_container(self.context) except: send("Error while indexing the index.", type='error') else: send("Index refreshed.") actions += form.Actions(*list(ControlPanelForm.actions))
class PortalConfig(EditFormBase): form_fields = form.FormFields(IPortalConfig) form_fields['validate_email'].custom_widget = ChoiceRadioWidget actions = form.Actions( form.Action( name='change', label=_(u'Change'), success='handle_success', failure='handle_failure'), ) template = ViewPageTemplateFile("config.pt") def setUpWidgets(self, ignore_request=False): data = {} ptool = getUtility(IPropertiesTool) charset = ptool.getProperty('default_charset', None) for name in getFieldNames(IPortalConfig): value = ptool.getProperty(name) try: value = value.decode(charset) except (AttributeError, UnicodeEncodeError): pass data[name] = value data['smtp_server'] = ptool.smtp_server() self.widgets = form.setUpDataWidgets( self.form_fields, self.prefix, self.context, self.request, data=data, ignore_request=ignore_request) def handle_success(self, action, data): ptool = getUtility(IPropertiesTool) ptool.editProperties(data) self.status = _(u"Portal settings changed.") self._setRedirect('portal_actions', 'global/configPortal')
class ContentAddFormBase(_EditFormMixin, form.PageAddForm): adapts(IFolderish, ICMFDefaultSkin, ITypeInformation) implementsOnly(IPageForm) security = ClassSecurityInfo() security.declareObjectPrivate() actions = form.Actions( form.Action(name='add', label=form._('Add'), condition=form.haveInputWidgets, success='handle_add', failure='handle_failure'), form.Action(name='cancel', label=_(u'Cancel'), validator='handle_cancel_validate', success='handle_cancel_success')) def __init__(self, context, request, ti): self.context = context self.request = request self.ti = ti security.declareProtected(AddPortalContent, '__call__') def __call__(self): container = self.context portal_type = self.ti.getId() # check allowed (sometimes redundant, but better safe than sorry) if not self.ti.isConstructionAllowed(container): raise AccessControl_Unauthorized('Cannot create %s' % portal_type) # check container constraints ttool = getUtility(ITypesTool) container_ti = ttool.getTypeInfo(container) if container_ti is not None and \ not container_ti.allowType(portal_type): raise ValueError('Disallowed subobject type: %s' % portal_type) return super(ContentAddFormBase, self).__call__() @property def label(self): obj_type = translate(self.ti.Title(), self.context) return _(u'Add ${obj_type}', mapping={'obj_type': obj_type}) @property def description(self): return self.ti.Description() #same as in form.AddFormBase but without action decorator def handle_add(self, action, data): self.createAndAdd(data) def handle_cancel_success(self, action, data): return self._setRedirect('portal_types', ('object/folderContents', 'object/view')) def create(self, data): id = data.pop('id', '') or '' factory = getUtility(IFactory, self.ti.factory) obj = factory(id=id, **data) obj._setPortalTypeName(self.ti.getId()) return obj def add(self, obj): container = self.context name = INameChooser(container).chooseName(obj.getId(), obj) obj.id = name container._setObject(name, obj) obj = container._getOb(name) obj_type = translate(obj.Type(), container) self.status = _(u'${obj_type} added.', mapping={'obj_type': obj_type}) self._finished_add = True self._added_obj = obj return obj def nextURL(self): obj = self._added_obj message = translate(self.status, self.context) if isinstance(message, unicode): message = message.encode(self._getBrowserCharset()) return '%s/%s?%s' % (obj.absolute_url(), self.ti.immediate_view, make_query(portal_status_message=message))
class TimeLineViewlet(viewlet.ViewletBase): """ tracker/timeline view: Chronological changes are aggregated from : bill workflow, bill audit, bill scheduling and bill event records. """ # evoque render = z3evoque.ViewTemplateFile("workspace_viewlets.html#timeline") # zpt #render = ViewPageTemplateFile('templates/timeline_viewlet.pt') # sqlalchemy give me a rough time sorting a union, # with hand coded sql it is much easier. # !+ get rid of the hard-coded sql sql_timeline = "" add_action = form.Actions( form.Action(_(u'add event'), success='handle_event_add_action'), ) for_display = True view_name = "Timeline" view_id = "unknown-timeline" def __init__(self, context, request, view, manager): self.context = context self.request = request self.__parent__ = view self.manager = manager self.query = None self.formatter = date.getLocaleFormatter(self.request, "dateTime", "medium") def handle_event_add_action(self, action, data): self.request.response.redirect(self.addurl) def update(self): """Refresh the query. """ # evaluate serialization of a dict, failure returns an empty dict def _eval_as_dict(s): try: d = eval(s) assert isinstance(d, dict) return d except (SyntaxError, TypeError, AssertionError): #debug.log_exc(sys.exc_info(), log_handler=log.info) return {} # NOTE: only *Change records have a "notes" dict attribute and the # content of this depends on the value of "atype" (see core/audit.py) item_id = self.context.parliamentary_item_id self.results = [ dict(atype=action, item_id=piid, description=desc, adate=date, notes=_eval_as_dict(notes)) for action, piid, desc, date, notes in queries.execute_sql(self.sql_timeline, item_id=item_id) ] # Filter out workflow draft items for anonymous users if get_principal_id() in ("zope.anybody", ): _draft_states = ("draft", "working_draft") def show_timeline_item(result): if result["atype"] == "workflow": if result["notes"].get("destination") in _draft_states: return False return True self.results = [ result for result in self.results if show_timeline_item(result) ] #change_cls = getattr(domain, "%sChange" % (self.context.__class__.__name__)) for r in self.results: # workflow if r["atype"] == "workflow": # description # the workflow transition change log stores the (unlocalized) # human title for the transition's destination workflow state # -- here we just localize what is supplied: r["description"] = _(r["description"]) # NOTE: we could elaborate an entirely custom description # from scratch e.g via interpolation of a template string: ''' if r["notes"].get("destination", ""): description = "%s %s" % ( _("some text"), _(misc.get_wf_state( self.context, r["notes"]["destination"]))) ''' # event elif r["atype"] == "event": # description r["description"] = """<a href="event/obj-%s">%s</a>""" % ( r["item_id"], _(r["description"])) # version elif r["atype"] == "version": # description try: r["description"] = """<a href="versions/obj-%s">%s</a>""" % ( r["notes"]["version_id"], _(r["description"])) except (KeyError, ): # no recorded version_id, just localize what is supplied r["description"] = _(r["description"]) # path = url.absoluteURL(self.context, self.request) self.addurl = '%s/event/add' % (path)
class Search(BatchFormMixin, EditFormBase): """Portal Search Form""" template = ViewPageTemplateFile("search.pt") results = ViewPageTemplateFile("results.pt") hidden_fields = form.FormFields(IBatchForm) form_fields = form.FormFields(ISearchSchema) form_fields['review_state'].custom_widget = ChoiceMultiSelectWidget form_fields['Subject'].custom_widget = ChoiceMultiSelectWidget form_fields['portal_type'].custom_widget = ChoiceMultiSelectWidget search = form.Actions( form.Action( name='search', label=_(u"Search"), success='handle_search', failure='handle_failure', ), ) # for handling searches from the search box image = form.Actions( form.Action( name='search.x', label=_(u"Search"), success='handle_search', failure='handle_failure', ), form.Action( name='search.y', label=_(u"Search"), success='handle_search', failure='handle_failure', ), ) actions = search + image @property @memoize def catalog(self): return getUtility(ICatalogTool) @property @memoize def is_anonymous(self): mtool = getUtility(IMembershipTool) return mtool.isAnonymousUser() @memoize def _getNavigationVars(self): data = {} if hasattr(self, 'hidden_widgets'): form.getWidgetsData(self.hidden_widgets, self.prefix, data) if hasattr(self, '_query'): data.update(self._query) else: data = self.request.form return data @property @memoize def search_fields(self): if self.is_anonymous: return self.form_fields.omit('review_state') else: return self.form_fields def setUpWidgets(self, ignore_request=False): if "form.b_start" in self.request.form \ or "b_start" in self.request.form: self.template = self.results super(Search, self).setUpWidgets(ignore_request) self.widgets = form.setUpWidgets(self.search_fields, self.prefix, self.context, self.request, ignore_request=ignore_request) def handle_search(self, action, data): for k, v in data.items(): if k in ('review_state', 'Title', 'Subject', 'Description', 'portal_type', 'listCreators', 'SearchableText'): if not v or v == u"None": del data[k] elif k == 'created' and v == EPOCH: del data[k] self._query = data self.template = self.results @memoize def _get_items(self): return self.catalog.searchResults(self._query) @memoize def listBatchItems(self): return ({ 'description': item.Description, 'icon': item.getIconURL, 'title': item.Title, 'type': item.Type, 'date': item.Date, 'url': item.getURL(), 'format': None } for item in self._getBatchObj())
class ContentsView(BatchViewBase, _EditFormMixin, form.PageForm): """Folder contents view""" template = ViewPageTemplateFile('folder_contents.pt') prefix = 'form' object_actions = form.Actions( form.Action(name='rename', label=_(u'Rename'), validator='validate_items', condition='has_subobjects', success='handle_rename', failure='handle_failure'), form.Action(name='cut', label=_(u'Cut'), condition='has_subobjects', validator='validate_items', success='handle_cut', failure='handle_failure'), form.Action(name='copy', label=_(u'Copy'), condition='has_subobjects', validator='validate_items', success='handle_copy', failure='handle_failure'), form.Action(name='paste', label=_(u'Paste'), condition='check_clipboard_data', success='handle_paste'), form.Action(name='delete', label=_(u'Delete'), condition='has_subobjects', validator='validate_items', success='handle_delete', failure='handle_failure')) delta_actions = form.Actions( form.Action(name='up', label=_(u'Up'), condition='is_orderable', validator='validate_items', success='handle_up', failure='handle_failure'), form.Action(name='down', label=_(u'Down'), condition='is_orderable', validator='validate_items', success='handle_down', failure='handle_failure')) absolute_actions = form.Actions( form.Action(name='top', label=_(u'Top'), condition='is_orderable', validator='validate_items', success='handle_top', failure='handle_failure'), form.Action(name='bottom', label=_(u'Bottom'), condition='is_orderable', validator='validate_items', success='handle_bottom', failure='handle_failure')) sort_actions = form.Actions( form.Action(name='sort_order', label=_(u'Set as Default Sort'), condition='can_sort_be_changed', validator='validate_items', success='handle_top', failure='handle_failure')) actions = object_actions + delta_actions + absolute_actions + sort_actions errors = () def __init__(self, *args, **kw): super(ContentsView, self).__init__(*args, **kw) self.form_fields = form.FormFields() self.delta_field = form.FormFields(IDeltaItem) self.contents = self.context.contentValues() def content_fields(self): """Create content field objects only for batched items""" f = IFolderItem['select'] contents = [] b_start = self._getBatchStart() key, reverse = self._get_sorting() fields = form.FormFields() for idx, item in enumerate(self._getBatchObj()): field = form.FormField(f, 'select', item.id) fields += form.FormFields(field) content = ContentProxy(item) if key == 'position': content.position = b_start + idx + 1 else: content.position = '...' contents.append(content) self.listBatchItems = contents return fields @memoize @decode def up_info(self): """Link to the contens view of the parent object""" up_obj = self.context.aq_inner.aq_parent mtool = getUtility(IMembershipTool) allowed = mtool.checkPermission(ListFolderContents, up_obj) if allowed: if IDynamicType.providedBy(up_obj): up_url = up_obj.getActionInfo('object/folderContents')['url'] return { 'icon': '%s/UpFolder_icon.gif' % self._getPortalURL(), 'id': up_obj.getId(), 'url': up_url } else: return {'icon': '', 'id': 'Root', 'url': ''} else: return {} def setUpWidgets(self, ignore_request=False): """Create widgets for the folder contents.""" super(ContentsView, self).setUpWidgets(ignore_request) self.widgets = form.setUpWidgets(self.content_fields(), self.prefix, self.context, self.request, ignore_request=ignore_request) self.widgets += form.setUpWidgets(self.delta_field, self.prefix, self.context, self.request, ignore_request=ignore_request) @memoize def _get_sorting(self): """How should the contents be sorted""" data = self._getHiddenVars() key = data.get('sort_key') if key: return (key, data.get('reverse', 0)) else: return self.context.getDefaultSorting() @memoize def _is_default_sorting(self, ): return self._get_sorting() == self.context.getDefaultSorting() @memoize def column_headings(self): key, reverse = self._get_sorting() columns = ({ 'sort_key': 'Type', 'title': _(u'Type'), 'colspan': '2' }, { 'sort_key': 'getId', 'title': _(u'Name') }, { 'sort_key': 'modified', 'title': _(u'Last Modified') }, { 'sort_key': 'position', 'title': _(u'Position') }) for column in columns: paras = {'form.sort_key': column['sort_key']} if key == column['sort_key'] \ and not reverse and key != 'position': paras['form.reverse'] = 1 query = urllib.urlencode(paras) column['url'] = '%s?%s' % (self._getViewURL(), query) return tuple(columns) @memoize def _get_items(self): key, reverse = self._get_sorting() items = self.contents return sort(items, ((key, 'cmp', reverse and 'desc' or 'asc'), )) def _get_ids(self, data): """Identify objects that have been selected""" ids = [ k[:-7] for k, v in data.items() if v is True and k.endswith('.select') ] return ids #Action conditions @memoize def has_subobjects(self, action=None): """Return false if the user cannot rename subobjects""" return bool(self.contents) @memoize def check_clipboard_data(self, action=None): """Any data in the clipboard""" return bool(self.context.cb_dataValid()) @memoize def can_sort_be_changed(self, action=None): """Returns true if the default sort key may be changed may be sorted for display""" items_move_allowed = self._checkPermission(ManageProperties) return items_move_allowed and not \ self._get_sorting() == self.context.getDefaultSorting() @memoize def is_orderable(self, action=None): """Returns true if the displayed contents can be reorded.""" (key, reverse) = self._get_sorting() return key == 'position' and len(self.contents) > 1 #Action validators def validate_items(self, action=None, data=None): """Check whether any items have been selected for the requested action.""" super(ContentsView, self).validate(action, data) if self._get_ids(data) == []: return [_(u"Please select one or more items first.")] else: return [] #Action handlers def handle_rename(self, action, data): """Redirect to rename view passing the ids of objects to be renamed""" # currently redirects to a PythonScript # should be replaced with a dedicated form self.request.form['ids'] = self._get_ids(data) keys = ",".join(self._getHiddenVars().keys() + ['ids']) # keys = 'b_start, ids, key, reverse' return self._setRedirect('portal_types', 'object/rename_items', keys) def handle_cut(self, action, data): """Cut the selected objects and put them in the clipboard""" ids = self._get_ids(data) try: self.context.manage_cutObjects(ids, self.request) if len(ids) == 1: self.status = _(u'Item cut.') else: self.status = _(u'Items cut.') except CopyError: self.status = _(u'CopyError: Cut failed.') except zExceptions_Unauthorized: self.status = _(u'Unauthorized: Cut failed.') return self._setRedirect('portal_types', 'object/folderContents') def handle_copy(self, action, data): """Copy the selected objects to the clipboard""" ids = self._get_ids(data) try: self.context.manage_copyObjects(ids, self.request) if len(ids) == 1: self.status = _(u'Item copied.') else: self.status = _(u'Items copied.') except CopyError: self.status = _(u'CopyError: Copy failed.') return self._setRedirect('portal_types', 'object/folderContents') def handle_paste(self, action, data): """Paste the objects from the clipboard into the folder""" try: result = self.context.manage_pasteObjects(self.request['__cp']) if len(result) == 1: self.status = _(u'Item pasted.') else: self.status = _(u'Items pasted.') except CopyError, error: self.status = _(u'CopyError: Paste failed.') self.request['RESPONSE'].expireCookie( '__cp', path='%s' % (self.request['BASEPATH1'] or "/")) except zExceptions_Unauthorized: self.status = _(u'Unauthorized: Paste failed.')