def test_interfaces(self):
        self.failUnless(IXMBooking.implementedBy(Booking))
        self.failUnless(IXMBooking.providedBy(Booking('blah')))

        self.failUnless(IXMIteration.implementedBy(Iteration))
        self.failUnless(IXMIteration.providedBy(Iteration('blah')))

        self.failUnless(IXMOffer.implementedBy(Offer))
        self.failUnless(IXMOffer.providedBy(Offer('blah')))

        self.failUnless(IXMProject.implementedBy(Project))
        self.failUnless(IXMProject.providedBy(Project('blah')))

        self.failUnless(IXMStory.implementedBy(Story))
        self.failUnless(IXMStory.providedBy(Story('blah')))

        self.failUnless(IXMTask.implementedBy(Task))
        self.failUnless(IXMTask.providedBy(Task('blah')))

        # BBB can be removed in release 2.1
        self.failUnless(IXMCustomer.implementedBy(Customer))
        self.failUnless(IXMCustomer.providedBy(Customer('blah')))

        self.failUnless(IXMCustomerFolder.implementedBy(CustomerFolder))
        self.failUnless(IXMCustomerFolder.providedBy(CustomerFolder('blah')))

        self.failUnless(IXMProjectFolder.implementedBy(ProjectFolder))
        self.failUnless(IXMProjectFolder.providedBy(ProjectFolder('blah')))

        self.failUnless(IXMProjectMember.implementedBy(ProjectMember))
        self.failUnless(IXMProjectMember.providedBy(ProjectMember('blah')))
    def xmChangeWorkflowState(self, uid, url):
        """Change the workflow state, currently only of a Task."""
        context = aq_inner(self.context)
        ksscore = self.getCommandSet('core')
        zopecommands = self.getCommandSet('zope')
        plonecommands = self.getCommandSet('plone')

        locking = ILockable(context, None)
        if locking is not None and not locking.can_safely_unlock():
            selector = ksscore.getHtmlIdSelector('plone-lock-status')
            zopecommands.refreshViewlet(selector, 'plone.abovecontent',
                                        'plone.lockinfo')
            plonecommands.refreshContentMenu()
            return self.render()

        (proto, host, path, query, anchor) = urlsplit(url)
        if not path.endswith('content_status_modify'):
            raise KSSExplicitError('only content_status_modify is handled')
        action = query.split("workflow_action=")[-1].split('&')[0]
        uid_catalog = getToolByName(context, 'uid_catalog')
        brain = uid_catalog(UID=uid)[0]
        obj = brain.getObject()
        # This may give a UnicodeDecodeError if the title has
        # non-ascii characters:
        # obj.content_status_modify(action)
        # So we do it manually, which is better anyway:
        wftool = getToolByName(context, 'portal_workflow')
        wftool.doActionFor(obj, action=action)
        if IXMStory.providedBy(self.context):
            # Only refresh content if the context is a Story,
            # otherwise you get too much tasks listed.
            selector = ksscore.getCssSelector('.contentViews')
            zopecommands.refreshViewlet(selector, 'plone.contentviews',
                                        'plone.contentviews')
            zopecommands.refreshProvider('.tasklist_table',
                                         'xm.tasklist.simple')
            plonecommands.refreshContentMenu()
        else:
            # In all other cases, we can at least refresh the part
            # that shows the workflow info for this item.
            wf_change = obj.restrictedTraverse('xm_workflow_change')
            html = wf_change()
            selector = ksscore.getHtmlIdSelector('id-%s' % uid)
            ksscore.replaceHTML(selector, html)
        self.issueAllPortalMessages()
        self.cancelRedirect()
    def xmChangeWorkflowState(self, uid, url):
        """Change the workflow state, currently only of a Task."""
        context = aq_inner(self.context)
        ksscore = self.getCommandSet('core')
        zopecommands = self.getCommandSet('zope')
        plonecommands = self.getCommandSet('plone')

        locking = ILockable(context, None)
        if locking is not None and not locking.can_safely_unlock():
            selector = ksscore.getHtmlIdSelector('plone-lock-status')
            zopecommands.refreshViewlet(selector, 'plone.abovecontent',
                                        'plone.lockinfo')
            plonecommands.refreshContentMenu()
            return self.render()

        (proto, host, path, query, anchor) = urlsplit(url)
        if not path.endswith('content_status_modify'):
            raise KSSExplicitError('only content_status_modify is handled')
        action = query.split("workflow_action=")[-1].split('&')[0]
        uid_catalog = getToolByName(context, 'uid_catalog')
        brain = uid_catalog(UID=uid)[0]
        obj = brain.getObject()
        # This may give a UnicodeDecodeError if the title has
        # non-ascii characters:
        # obj.content_status_modify(action)
        # So we do it manually, which is better anyway:
        wftool = getToolByName(context, 'portal_workflow')
        wftool.doActionFor(obj, action=action)
        if IXMStory.providedBy(self.context):
            # Only refresh content if the context is a Story,
            # otherwise you get too much tasks listed.
            selector = ksscore.getCssSelector('.contentViews')
            zopecommands.refreshViewlet(selector, 'plone.contentviews',
                                        'plone.contentviews')
            zopecommands.refreshProvider('.tasklist_table',
                                         'xm.tasklist.simple')
            plonecommands.refreshContentMenu()
        else:
            # In all other cases, we can at least refresh the part
            # that shows the workflow info for this item.
            wf_change = obj.restrictedTraverse('xm_workflow_change')
            html = wf_change()
            selector = ksscore.getHtmlIdSelector('id-%s' % uid)
            ksscore.replaceHTML(selector, html)
        self.issueAllPortalMessages()
        self.cancelRedirect()
 def update_story_viewlets(self):
     """Refresh story viewlets.
     """
     context = aq_inner(self.context)
     if IXMStory.providedBy(context):
         # only do this if the context is actually a Story.
         zope = self.view.getCommandSet('zope')
         zope.refreshProvider('.tasklist_table',
                              'xm.tasklist.simple')
         # Remove expanded task form and button if it is there.
         ksscore = self.view.getCommandSet('core')
         selector1 = ksscore.getHtmlIdSelector('task-form-expanded')
         ksscore.replaceHTML(
             selector1, u'<!-- Removed expanded task form -->')
         selector2 = ksscore.getHtmlIdSelector('task-form-button')
         ksscore.replaceHTML(
             selector2, u'<!-- Removed task form button -->')
         # Refresh unexpanded task form.
         zope.refreshProvider('#task-form', 'xm.task_form')
         # Refresh the details box provider
         zope.refreshProvider('.xm-details',
                              'xm.story.detailsbox')
 def update_story_viewlets(self):
     """Refresh story viewlets.
     """
     context = aq_inner(self.context)
     if IXMStory.providedBy(context):
         # only do this if the context is actually a Story.
         zope = self.view.getCommandSet('zope')
         zope.refreshProvider('.tasklist_table',
                              'xm.tasklist.simple')
         # Remove expanded task form and button if it is there.
         ksscore = self.view.getCommandSet('core')
         selector1 = ksscore.getHtmlIdSelector('task-form-expanded')
         ksscore.replaceHTML(
             selector1, '<!-- Removed expanded task form -->')
         selector2 = ksscore.getHtmlIdSelector('task-form-button')
         ksscore.replaceHTML(
             selector2, '<!-- Removed task form button -->')
         # Refresh unexpanded task form.
         zope.refreshProvider('#task-form', 'xm.task_form')
         # Refresh the details box provider
         zope.refreshProvider('.xm-details',
                              'xm.story.detailsbox')