class ExampleWorkflowConstraintDefinition(constraints.ConstraintDefinition):

    @message(_('The parent object needs to be published first.'))
    @error_on(interfaces.PUBLISH)
    @warning_on(interfaces.SUBMIT)
    def parent_needs_to_be_published(self):
        return self.state().is_parent_published()

    @message(_('The child object ${item} is still published.'))
    @warning_on(interfaces.RETRACT)
    def retract_children_first(self):
        return list(self.state().get_published_children())

    @message(_('The referenced object ${item} is not yet published.'))
    @warning_on(interfaces.PUBLISH, interfaces.SUBMIT)
    def references_should_be_published(self):
        main_obj = get_main_obj_belonging_to(self.context)

        def reference_is_not_reference_to_self(target_main_obj):
            return target_main_obj != main_obj

        return list(filter(reference_is_not_reference_to_self,
                           map(get_main_obj_belonging_to,
                               self.state().get_unpublished_references())))

    @message(_('The referenced object ${item} is still published.'))
    @warning_on(interfaces.DELETE, interfaces.RETRACT)
    def references_may_be_retracted_too(self):
        return list(map(get_main_obj_belonging_to, self.state().get_published_references()))
class IRealm(Interface):

    active = Bool(title=_(u'label_realm_active', default=u'Active'))

    url = URI(title=_(u'label_realm_url', u'URL to the Plone-Site'))

    username = TextLine(title=_(u'label_realm_username', u'Username'))

    password = Password(title=_(u'label_realm_password', u'Password'))
Example #3
0
class ConstraintDefinition1(constraints.ConstraintDefinition):
    @constraints.message(_('Fohoo'))
    @constraints.error_on(interfaces.PUBLISH)
    @constraints.warning_on(interfaces.SUBMIT)
    def foo(self):
        return False

    @constraints.message(_('Bahar'))
    @constraints.error_on(interfaces.PUBLISH, interfaces.SUBMIT)
    def bar(self):
        return False
    def __call__(self, *args, **kwargs):
        redirect_to = None

        self.key = int(self.request.get('job'))
        self.job = self.queue.get_executed_job_by_key(self.key)

        if self.request.get('button.requeue'):
            if self.job.json_file_exists():
                self.queue.remove_executed_job(self.key)
                self.job.move_jsonfile_to(self.config.getDataFolder())
                self.queue.appendJob(self.job)
                msg = _(u'info_requeued_job',
                        default=u'The job has been moved to the queue.')
                IStatusMessage(self.request).addStatusMessage(msg,
                                                              type='info')
                redirect_to = './@@publisher-config'
            else:
                msg = _(u'error_job_data_file_missing',
                        default=u'The data file of the job is missing.')
                IStatusMessage(self.request).addStatusMessage(msg,
                                                              type='error')

        if self.request.get('button.delete'):
            self.queue.remove_executed_job(self.key)
            if self.job.json_file_exists():
                self.job.removeJob()
            msg = _(u'info_job_deleted',
                    default=u'The job has been deleted.')
            IStatusMessage(self.request).addStatusMessage(msg,
                                                          type='info')
            redirect_to = './@@publisher-config-listExecutedJobs'

        if self.request.get('button.execute'):
            if self.job.json_file_exists():
                portal = self.context.portal_url.getPortalObject()
                execview = portal.restrictedTraverse(
                    '@@publisher.executeQueue')
                execview.execute_single_job(self.job)
                msg = _(u'info_job_executed',
                        default=u'The job has been executed.')
                IStatusMessage(self.request).addStatusMessage(msg,
                                                              type='info')
            else:
                msg = _(u'error_job_data_file_missing',
                        default=u'The data file of the job is missing.')
                IStatusMessage(self.request).addStatusMessage(msg,
                                                              type='error')
            redirect_to = './@@publisher-config-executed-job-details?job=' + \
                str(self.key)

        if redirect_to:
            return self.request.RESPONSE.redirect(redirect_to)

        return super(ExecutedJobDetails, self).__call__(*args, **kwargs)
    def __call__(self, no_response=False, msg=None, *args, **kwargs):
        """
        This is a copy from the orginal publisher.publish view for
        PloneFormGen.
        it also publishs all its contents
        """
        self.logger = getLogger()

        # get username
        user = self.context.portal_membership.getAuthenticatedMember()
        username = user.getUserName()
        # create Job
        queue = Queue(self.context)
        queue.createJob("push", self.context, username)
        self.logger.info(
            'Created "%s" Job for "%s" at %s' % ("push", self.context.Title(), "/".join(self.context.getPhysicalPath()))
        )

        # Get all items recursively and add theme to the queue
        def add_item_to_queue(items):
            for item in items:
                queue.createJob("push", item, username)
                subitems = item.objectValues()
                if subitems:
                    add_item_to_queue(subitems)

        add_item_to_queue(self.context.objectValues())

        # status message
        if msg is None:
            msg = _(u"This object has been added to the queue.")
        IStatusMessage(self.request).addStatusMessage(msg, type="info")
        if not no_response:
            return self.request.RESPONSE.redirect("./view")
    def get_translated_cleanup_prompt(self):
        """Returns the converted prompt string which is displayed when
        clicking on "cleanup".

        """
        return self.context.translate(_(
                u'prompt_cleanup',
                default=u'Are you shure to delete all executed jobs?'))
    def get_translated_cleanup_prompt(self):
        """Returns the converted prompt string which is displayed when
        clicking on "cleanup".

        """
        return self.context.translate(_(
                u'prompt_cleanup',
                default=u'Are you shure to delete all executed jobs?'))
class CreateRealmForm(form.Form):
    """
    The CreateRealmForm is a z3c-form used for adding a new Realm
    instance to the publisher configuration.

    @cvar fields:           fields from the schema IRealmSchema
    @cvar ignoreContext:    do not use context (z3c-form setting)
    @cvar label:            label of the form
    """
    implements(IWrappedForm)

    fields = field.Fields(IRealmSchema)
    ignoreContext = True
    label = u'Add Realm'

    @button.buttonAndHandler(_(u'button_save_realm', default=u'Save Realm'))
    def handleAdd(self, action):
        """
        This handler handles a click on the "Add Realm"-Button.
        If no errors occured, it adds a new Realm to the Config.
        @param action:      ActionInfo object provided by z3c.form
        @return:            None (form is shown) or Response-redirect
        """
        data, errors = self.extractData()
        config = IConfig(self.context)
        if len(errors)==0:
            assert config.is_update_realms_possible()
            # url + username has to be unique
            for realm in config.getRealms():
                if realm.url==data['url'] and realm.username==data['username']:
                    self.statusMessage(
                        'This URL / Username combination already exists!',
                        'error')
                    return
            kwargs = {
                'active': data['active'] and 1 or 0,
                'url': data['url'],
                'username': data['username'],
                'password': data['password'],
                }
            realm = Realm(**kwargs)
            config.appendRealm(realm)
            self.statusMessage('Added realm successfully')
            return self.request.RESPONSE.redirect('./@@publisher-config')

    def statusMessage(self, message, type='info'):
        """
        Adds a Plone statusMessage to the session.
        @param message:         Message to display
        @type message:          string
        @param type:            Type of the message [info|warning|error]
        @type type:             string
        @return:                None
        """
        IStatusMessage(self.request).addStatusMessage(
            message,
            type=type)
Example #9
0
    def __call__(self, event, no_response=False, msg=None):
        if IPreventPublishing.providedBy(self.context):
            return 'prevented'

        if publisher_jobs_are_disabled():
            return 'disabled'

        self.logger = getLogger()
        # is the object blacklisted?
        if IPathBlacklist(self.context).is_blacklisted():
            self.logger.warning(
                'Could not create move job for blacklisted object (%s at %s)' %
                (self.context.Title(), '/'.join(
                    self.context.getPhysicalPath())))
            if not no_response:
                return self.request.RESPONSE.redirect('./view')
            return False

        # This View should not be executed at the PloneSiteRoot
        if IPloneSiteRoot.providedBy(self.context):
            raise Exception('Not allowed on PloneSiteRoot')

        # get username
        user = self.context.portal_membership.getAuthenticatedMember()
        username = user.getUserName()

        # create Job
        portal = self.context.portal_url.getPortalObject()
        queue = IQueue(portal)

        additional_data = {
            'move_data': {
                'newName': event.newName,
                'newParent': get_site_relative_path(event.newParent),
                'newTitle': event.object.Title().decode('utf-8'),
                'oldName': event.oldName,
                'oldParent': get_site_relative_path(event.oldParent),
            }
        }

        queue.createJob('move',
                        self.context,
                        username,
                        additional_data=additional_data)
        self.logger.debug('Created "%s" Job for "%s" at %s' % (
            'move',
            self.context.Title(),
            '/'.join(self.context.getPhysicalPath()),
        ))

        # status message
        if msg is None:
            msg = _(u'Object move/rename action has been added to the queue.')

        IStatusMessage(self.request).addStatusMessage(msg, type='info')
        if not no_response:
            return self.request.RESPONSE.redirect('./view')
Example #10
0
class ConstraintDefinition2(constraints.ConstraintDefinition):
    @constraints.message(_('X ${item} Y'))
    @constraints.error_on(interfaces.PUBLISH)
    def baz(self):
        foo = Dummy(absolute_url=lambda: 'http://host/foo',
                    Title=lambda: 'Foo')
        bar = Dummy(absolute_url=lambda: 'http://host/bar',
                    Title=lambda: 'Bar')
        return [foo, bar]
    def action(self, REQUEST=None):
        if self.request.get('button.requeue'):
            if self.job.json_file_exists():
                self.queue.remove_executed_job(self.key)
                self.job.move_jsonfile_to(self.config.getDataFolder())
                self.queue.appendJob(self.job)
                msg = _(u'info_requeued_job',
                        default=u'The job has been moved to the queue.')
                IStatusMessage(self.request).addStatusMessage(msg,
                                                              type='info')
                return './@@publisher-config'
            else:
                msg = _(u'error_job_data_file_missing',
                        default=u'The data file of the job is missing.')
                IStatusMessage(self.request).addStatusMessage(msg,
                                                              type='error')

        if self.request.get('button.delete'):
            self.queue.remove_executed_job(self.key)
            if self.job.json_file_exists():
                self.job.removeJob()
            msg = _(u'info_job_deleted',
                    default=u'The job has been deleted.')
            IStatusMessage(self.request).addStatusMessage(msg,
                                                          type='info')
            return './@@publisher-config-listExecutedJobs'

        if self.request.get('button.execute'):
            if self.job.json_file_exists():
                portal = self.context.portal_url.getPortalObject()
                execview = portal.restrictedTraverse(
                    '@@publisher.executeQueue')
                execview.execute_single_job(self.job)
                msg = _(u'info_job_executed',
                        default=u'The job has been executed.')
                IStatusMessage(self.request).addStatusMessage(msg,
                                                              type='info')
            else:
                msg = _(u'error_job_data_file_missing',
                        default=u'The data file of the job is missing.')
                IStatusMessage(self.request).addStatusMessage(msg,
                                                              type='error')
            return './@@publisher-config-executed-job-details?job=' + \
                str(self.key)
 def __call__(self, *args, **kwargs):
     id = self.request.get('id', '')
     realm = self.getRealmById(id)
     if not realm:
         self.statusMessage(_(u'error_realm_not_found',
                              default=u'Could not find realm'), 'error')
     else:
         responseText = sendRequestToRealm({}, realm,
                                           'publisher.testConnection')
         if responseText=='ok':
             self.statusMessage(_(u'info_realm_connection_okay',
                                  default=u'Connection okay'))
         else:
             self.statusMessage(
                 _(u'error_realm_connection_failed',
                   default=u'Connection to realm failed: ${msg}',
                   mapping=dict(msg=responseText.decode('utf-8'))),
                 type='error')
     return self.request.RESPONSE.redirect('./@@publisher-config')
 def __call__(self, *args, **kwargs):
     id = self.request.get('id', '')
     realm = self.getRealmById(id)
     if not realm:
         self.statusMessage(_(u'error_realm_not_found',
                              default=u'Could not find realm'), 'error')
     else:
         responseText = sendRequestToRealm({}, realm,
                                           'publisher.testConnection')
         if responseText=='ok':
             self.statusMessage(_(u'info_realm_connection_okay',
                                  default=u'Connection okay'))
         else:
             self.statusMessage(
                 _(u'error_realm_connection_failed',
                   default=u'Connection to realm failed: ${msg}',
                   mapping=dict(msg=responseText.decode('utf-8'))),
                 type='error')
     return self.request.RESPONSE.redirect('./@@publisher-config')
 def __call__(self, *args, **kwargs):
     delete = self.request.get('delete', None)
     if delete:
         if self.config.removePathFromBlacklist(delete):
             msg = _(u'info_path_removed',
                     default=u'Removed path ${path} from blacklist',
                     mapping={'path': delete})
             IStatusMessage(self.request).addStatusMessage(msg, type='info')
         return self.request.RESPONSE.redirect('./@@publisher-config-blacklist')
     return super(PathBlacklistView, self).__call__(*args, **kwargs)
Example #15
0
    def __call__(self, no_response=False, msg=None, *args, **kwargs):
        """
        The __call__ method is used to execute the BrowserView. It creates and
        adds a "PUSH"-Job on the current context to the queue.
        @param args:    list of unnamed arguments
        @type args:     list
        @param kwargs:  dict of named keyword-arguments
        @type kwargs:   dict
        @return:        Redirect to object`s default view
        """

        if IPreventPublishing.providedBy(self.context):
            return 'prevented'

        if publisher_jobs_are_disabled():
            return 'disabled'

        self.logger = getLogger()
        # is the object blacklisted?
        if IPathBlacklist(self.context).is_blacklisted():
            self.logger.warning('Could not create push job for blacklisted '+\
                                    'object (%s at %s)' % (
                    self.context.Title(),
                    '/'.join(self.context.getPhysicalPath())))
            if not no_response:
                return self.request.RESPONSE.redirect('./view')
            return False

        # mle: now its possible to execite this view on plonesiteroot
        # This View should not be executed at the PloneSiteRoot
        #if IPloneSiteRoot.providedBy(self.context):
        #    raise Exception('Not allowed on PloneSiteRoot')
        # get username
        user = self.context.portal_membership.getAuthenticatedMember()
        username = user.getUserName()
        # create Job
        portal = self.context.portal_url.getPortalObject()
        queue = IQueue(portal)
        queue.createJob('push', self.context, username)
        self.logger.debug('Created "%s" Job for "%s" at %s' % (
                'push',
                self.context.Title(),
                '/'.join(self.context.getPhysicalPath()),
                ))

        # status message
        if msg is None:
            msg = _(u'This object has been added to the queue.')
        IStatusMessage(self.request).addStatusMessage(
            msg,
            type='info'
            )
        if not no_response:
            return self.request.RESPONSE.redirect('./view')
Example #16
0
 def __call__(self, *args, **kwargs):
     delete = self.request.get('delete', None)
     if delete:
         if self.config.removePathFromBlacklist(delete):
             msg = _(u'info_path_removed',
                     default=u'Removed path ${path} from blacklist',
                     mapping={'path': delete})
             IStatusMessage(self.request).addStatusMessage(msg, type='info')
         return self.request.RESPONSE.redirect(
             './@@publisher-config-blacklist')
     return super(PathBlacklistView, self).__call__(*args, **kwargs)
Example #17
0
class AddPathForm(form.Form):
    implements(IWrappedForm)

    fields = field.Fields(IBlacklistPathSchema)
    ignoreContext = True
    label = _(u'form_label_add_path', default=u'Add path')

    @button.buttonAndHandler(_(u'button_add_path', default=u'Add path'))
    def handleAdd(self, action):
        portal = self.context.portal_url.getPortalObject()
        config = IConfig(portal)
        data, errors = self.extractData()
        if not len(errors):
            path = data.get('path').strip()
            if not path.startswith('/'):
                raise Exception('Path does not start with /')
            config.appendPathToBlacklist(path)
            message = _(u'info_path_added', default=u'Path added')
            IStatusMessage(self.request).addStatusMessage(message, type='info')
            return self.request.RESPONSE.redirect(
                './@@publisher-config-blacklist')
Example #18
0
 def handleAdd(self, action):
     portal = self.context.portal_url.getPortalObject()
     config = IConfig(portal)
     data, errors = self.extractData()
     if not len(errors):
         path = data.get('path').strip()
         if not path.startswith('/'):
             raise Exception('Path does not start with /')
         config.appendPathToBlacklist(path)
         message = _(u'info_path_added', default=u'Path added')
         IStatusMessage(self.request).addStatusMessage(message, type='info')
         return self.request.RESPONSE.redirect(
             './@@publisher-config-blacklist')
Example #19
0
    def __call__(self, no_response=False, msg=None, *args, **kwargs):
        """
        Add the current context as delete-job to the queue, creates a status
        message to inform the user and returns to the default view.
        @param args:    list of unnamed arguments
        @type args:     list
        @param kwargs:  dict of named keyword-arguments
        @type kwargs:   dict
        @return:        Redirect to object`s default view
        """

        if IPreventPublishing.providedBy(self.context):
            return 'prevented'

        if publisher_jobs_are_disabled():
            return 'disabled'

        self.logger = getLogger()
        # is the object blacklisted?
        if IPathBlacklist(self.context).is_blacklisted():
            self.logger.warning('Could not create delete job for blacklisted '
                                'object (%s at %s)' % (
                    self.context.Title(),
                    '/'.join(self.context.getPhysicalPath())))
            if not no_response:
                return self.request.RESPONSE.redirect('./view')
            return False

        # This view should not be executed at the PloneSiteRoot
        if IPloneSiteRoot.providedBy(self.context):
            raise Exception('Not allowed on PloneSiteRoot')
        # get username
        user = self.context.portal_membership.getAuthenticatedMember()
        username = user.getUserName()
        # create Job
        portal = self.context.portal_url.getPortalObject()
        queue = IQueue(portal)
        queue.createJob('delete', self.context, username)
        self.logger.debug('Created "%s" Job for "%s" at %s' % (
                'delete',
                self.context.Title(),
                '/'.join(self.context.getPhysicalPath()),
                ))

        # status message
        if msg is None:
            msg = _(u'This object will be deleted at the remote sites.')
        add_transaction_aware_status_message(self.request, msg, type='info')

        if not no_response:
            return self.request.RESPONSE.redirect('./view')
Example #20
0
    def __call__(self, no_response=False, msg=None, recursive=True):
        if IPreventPublishing.providedBy(self.context):
            return 'prevented'

        if publisher_jobs_are_disabled():
            return 'disabled'

        self.logger = getLogger()
        # is the object blacklisted?
        if IPathBlacklist(self.context).is_blacklisted():
            self.logger.warning(
                'Could not create push job for blacklisted object (%s at %s)' %
                (self.context.Title(), '/'.join(
                    self.context.getPhysicalPath())))
            if not no_response:
                return self.request.RESPONSE.redirect('./view')
            return False

        event.notify(BeforePublishEvent(self.context))

        # mle: now its possible to execite this view on plonesiteroot
        # This View should not be executed at the PloneSiteRoot
        # if IPloneSiteRoot.providedBy(self.context):
        #    raise Exception('Not allowed on PloneSiteRoot')
        # get username
        user = self.context.portal_membership.getAuthenticatedMember()
        username = user.getUserName()

        # create Job
        portal = self.context.portal_url.getPortalObject()
        queue = IQueue(portal)
        queue.createJob('push', self.context, username)
        self.logger.debug('Created "%s" Job for "%s" at %s' % (
            'push',
            self.context.Title(),
            '/'.join(self.context.getPhysicalPath()),
        ))

        if recursive and base_hasattr(self.context, 'contentValues'):
            # Use contentValues for implicit ftw.trash compatibility.
            for obj in filter(belongs_to_parent, self.context.contentValues()):
                obj.restrictedTraverse('@@publisher.publish')(no_response=True,
                                                              msg=msg)

        # status message
        if msg is None:
            msg = _(u'This object has been added to the queue.')
        IStatusMessage(self.request).addStatusMessage(msg, type='info')
        if not no_response:
            return self.request.RESPONSE.redirect('./view')
 def handleAdd(self, action):
     portal = self.context.portal_url.getPortalObject()
     config = IConfig(portal)
     data, errors = self.extractData()
     if not len(errors):
         path = data.get('path').strip()
         if not path.startswith('/'):
             raise Exception('Path does not start with /')
         config.appendPathToBlacklist(path)
         message = _(u'info_path_added',
                     default=u'Path added')
         IStatusMessage(self.request).addStatusMessage(
             message, type='info')
         return self.request.RESPONSE.redirect('./@@publisher-config-blacklist')
Example #22
0
    def __call__(self, no_response=False, msg=None):
        if IPreventPublishing.providedBy(self.context):
            return 'prevented'

        if publisher_jobs_are_disabled():
            return 'disabled'

        self.logger = getLogger()
        # is the object blacklisted?
        if IPathBlacklist(self.context).is_blacklisted():
            self.logger.warning('Could not create delete job for blacklisted '
                                'object (%s at %s)' %
                                (self.context.Title(), '/'.join(
                                    self.context.getPhysicalPath())))
            if not no_response:
                return self.request.RESPONSE.redirect('./view')
            return False

        # This view should not be executed at the PloneSiteRoot
        if IPloneSiteRoot.providedBy(self.context):
            raise Exception('Not allowed on PloneSiteRoot')

        # get username
        user = self.context.portal_membership.getAuthenticatedMember()
        username = user.getUserName()

        # create Job
        portal = self.context.portal_url.getPortalObject()
        queue = IQueue(portal)
        queue.createJob('delete', self.context, username)
        self.logger.debug('Created "%s" Job for "%s" at %s' % (
            'delete',
            self.context.Title(),
            '/'.join(self.context.getPhysicalPath()),
        ))

        # status message
        if msg is None:
            msg = _(u'This object will be deleted at the remote sites.')
        add_transaction_aware_status_message(self.request, msg, type='info')

        if not no_response:
            return self.request.RESPONSE.redirect('./view')
Example #23
0
def download(self, REQUEST=None, RESPONSE=None):
    """Download the saved data
    """
    url_tool = getToolByName(self, 'portal_url')
    config = IConfig(url_tool.getPortalObject())
    pub_state = getMultiAdapter((self, REQUEST), IPublisherContextState)
    realms = config.getRealms()
    download_format = getattr(self, 'DownloadFormat', 'csv')

    if len(realms) == 0 or not pub_state.is_parent_published():
        if download_format == 'tsv':
            return self.download_tsv(REQUEST, RESPONSE)
        else:
            assert download_format == 'csv', 'Unknown download format'
            return self.download_csv(REQUEST, RESPONSE)

    elif len(realms) == 1:
        data = {'uid': self.UID(), 'download_format': download_format}
        return_data_realm = sendRequestToRealm(data,
                                               realms[0],
                                               'formgen_get_saved_data')
        return_data_this = self.getSavedFormInputForEdit()
        return_data = '{}{}'.format(return_data_realm, return_data_this)

        filename = self.id
        if filename.find('.') < 0:
            filename = '%s.%s' % (filename, download_format)
        header_value = contentDispositionHeader('attachment',
                                                self.getCharset(),
                                                filename=filename)
        RESPONSE.setHeader("Content-Disposition", header_value)
        sep_type = download_format == 'csv' and 'comma' or 'tab'
        RESPONSE.setHeader("Content-Type",
                           'text/%s-separated-values;'
                           'charset=%s' % (sep_type, self.getCharset()))

        return return_data

    else:
        messages = IStatusMessage(self.request)
        messages.add(_(u"couldn't determine correct realm to fetch from."),
                     type=u"error")
        return RESPONSE.redirect(self.context.absolute_url())
def download(self, REQUEST=None, RESPONSE=None):
    """Download the saved data
    """
    url_tool = getToolByName(self, 'portal_url')
    config = IConfig(url_tool.getPortalObject())
    pub_state = getMultiAdapter((self, REQUEST), IPublisherContextState)
    realms = config.getRealms()
    download_format = getattr(self, 'DownloadFormat', 'csv')

    if len(realms) == 0 or not pub_state.is_parent_published():
        if download_format == 'tsv':
            return self.download_tsv(REQUEST, RESPONSE)
        else:
            assert download_format == 'csv', 'Unknown download format'
            return self.download_csv(REQUEST, RESPONSE)

    elif len(realms) == 1:
        data = {'uid': self.UID(), 'download_format': download_format}
        return_data = sendRequestToRealm(data,
                                         realms[0],
                                         'formgen_get_saved_data')
        filename = self.id
        if filename.find('.') < 0:
            filename = '%s.%s' % (filename, download_format)
        header_value = contentDispositionHeader('attachment',
                                                self.getCharset(),
                                                filename=filename)
        RESPONSE.setHeader("Content-Disposition", header_value)
        sep_type = download_format == 'csv' and 'comma' or 'tab'
        RESPONSE.setHeader("Content-Type",
                           'text/%s-separated-values;'
                           'charset=%s' % (sep_type, self.getCharset()))
        return return_data

    else:
        messages = IStatusMessage(self.request)
        messages.add(_(u"couldn't determine correct realm to fetch from."),
                     type=u"error")
        return RESPONSE.redirect(self.context.absolute_url())
from z3c.form import field
from z3c.form import form
from z3c.form import interfaces
from zope.component import getUtility
from zope.interface import implements
from zope.publisher.interfaces import Retry
import datetime
import md5


EXECUTED_JOBS_BATCH_SIZE = 100


# lets translate the actions with i18ndude
TRANSLATED_ACTIONS = {
    'push': _(u'action_push', default=u'Push'),
    'move': _(u'action_move', default=u'Move'),
    'delete': _(u'action_delete', default=u'Delete'),
    }


# -- Forms

class CreateRealmForm(form.Form):
    """
    The CreateRealmForm is a z3c-form used for adding a new Realm
    instance to the publisher configuration.

    @cvar fields:           fields from the schema IRealmSchema
    @cvar ignoreContext:    do not use context (z3c-form setting)
    @cvar label:            label of the form
    def _get_data(self):
        columns = dict(ListExecutedJobs.COLUMNS)
        i18n_details = self.context.translate(_(
                u'link_job_details',
                default=u'Details'))
        i18n_requeu = self.context.translate(_(
                u'link_requeue_job',
                default='Requeue'))
        # get a batched part of the executed jobs. But we need to start
        # batching at the end, get the batch forward and then reverse,
        # because we want the newest job at the top.
        b_start = int(self.request.get('b_start', 0))
        jobs_length = self.queue.get_executed_jobs_length()
        end = jobs_length - b_start
        start = end - EXECUTED_JOBS_BATCH_SIZE
        if start < 0:
            start = 0
        entries = list(self.queue.get_executed_jobs(start, end))
        entries.reverse()
        for key, job in entries:
            state = job.get_latest_executed_entry()
            state_name = getattr(state, 'localized_name', None)
            if state_name:
                state_name = self.context.translate(state_name)
            else:
                state_name = state.__class__.__name__
            if isinstance(state, states.ErrorState):
                colored_state = '<span class="error" style="color:red;">' +\
                    '%s</span>' % self.context.translate(state_name)
            elif isinstance(state, states.WarningState):
                colored_state = '<span class="error" style="color:orange;">' +\
                    '%s</span>' % self.context.translate(state_name)
            else:
                colored_state = '<span class="success">%s</span>' % state_name
            date = 'unknown'
            try:
                date = job.executed_list[-1]['date'].strftime('%d.%m.%Y %H:%M')
            except (ConflictError, Retry):
                raise
            except:
                pass
            ctrl = ' '.join((
                    '<a href="./@@publisher-config-executed-job-details' +\
                        '?job=%s">%s</a>' % (key, i18n_details),
                    '|',
                    '<a href="./@@publisher-config-listExecutedJobs' +\
                        '?requeue.job=%s">%s</a>' % (key, i18n_requeu),
                    ))
            shortened_title = job.objectTitle
            maximum_length = 35

            if len(shortened_title) > maximum_length:
                try:
                    shortened_title = shortened_title.decode('utf8')
                    shortened_title = shortened_title[:maximum_length] + \
                                      u' ...'
                    shortened_title = shortened_title.encode('utf8')
                except (ConflictError, Retry):
                    raise
                except:
                    pass
            yield {
                columns['date']: date,
                columns['title']: '<a href="%s" title="%s">%s</a>' % (
                    job.objectPath + '/view',
                    job.objectTitle,
                    shortened_title),
                columns['action']: TRANSLATED_ACTIONS.get(job.action,
                                                          job.action),
                columns['state']: colored_state,
                columns['username']: job.username,
                columns['']: ctrl,
                }
from zope.interface import implements
from zope.publisher.interfaces import Retry
import datetime
import md5

try:
    from plone.protect.interfaces import IDisableCSRFProtection
except ImportError:
    IDisableCSRFProtection = None

EXECUTED_JOBS_BATCH_SIZE = 100


# lets translate the actions with i18ndude
TRANSLATED_ACTIONS = {
    'push': _(u'action_push', default=u'Push'),
    'move': _(u'action_move', default=u'Move'),
    'delete': _(u'action_delete', default=u'Delete'),
    }


# -- Forms

class CreateRealmForm(form.Form):
    """
    The CreateRealmForm is a z3c-form used for adding a new Realm
    instance to the publisher configuration.

    @cvar fields:           fields from the schema IRealmSchema
    @cvar ignoreContext:    do not use context (z3c-form setting)
    @cvar label:            label of the form
class EditRealmForm(form.EditForm):
    """
    The EditRealmForm is used for editing a Realm object.

    @cvar fields:           fields from the schema IRealmSchema
    @cvar ignoreContext:    do not use context (z3c-form setting)
    @cvar label:            label of the form
    """
    implements(IWrappedForm)

    fields = field.Fields(IEditRealmSchema)
    ignoreContext = True
    label = u'Edit Realm'

    def updateWidgets(self):
        """
        Updates the widgets (z3c-form method).
        Customized for adding a HIDDEN_MODE-Flag to the ID-field.
        """
        super(EditRealmForm, self).updateWidgets()
        self.widgets['id'].mode = interfaces.HIDDEN_MODE

    @button.buttonAndHandler(_(u'button_save_realm', default=u'Save Realm'))
    def handleSave(self, action):
        """
        """
        data, errors = self.extractData()
        config = IConfig(self.context)
        assert config.is_update_realms_possible()
        if len(errors)==0:
            # get realm
            currentRealm = self.getRealmById(data['id'])
            if not currentRealm:
                raise Exception('Could not find realm')
            # no other realm should have same url+username
            for realm in config.getRealms():
                if realm!=currentRealm:
                    if realm.username==data['username'] and\
                       realm.url==data['url']:
                        self.statusMessage(
                            'This URL / Username combination already exists!',
                            )
                        return
            # update realm
            currentRealm.active = data['active'] and 1 or 0
            currentRealm.url = data['url']
            currentRealm.username = data['username']
            if data['password'] and len(data['password'])>0:
                currentRealm.password = data['password']
            self.statusMessage('Updated realm successfully')
            return self.request.RESPONSE.redirect('./@@publisher-config')

    def statusMessage(self, message, type='info'):
        IStatusMessage(self.request).addStatusMessage(
            message,
            type=type)

    def makeRealmId(self, realm):
        return md5.md5('%s-%s' % (realm.url, realm.username)).hexdigest()

    def getRealmById(self, id):
        for realm in IConfig(self.context).getRealms():
            if self.makeRealmId(realm)==id:
                return realm
        return None
Example #29
0
    def __call__(self, event, no_response=False, msg=None, *args, **kwargs):
        """
        Creates a "rename" job for the current item(s)
        @param args:    list of unnamed arguments
        @type args:     list
        @param kwargs:  dict of named keyword-arguments
        @type kwargs:   dict
        @return:        Redirect to object`s default view
        """

        if IPreventPublishing.providedBy(self.context):
            return 'prevented'

        if publisher_jobs_are_disabled():
            return 'disabled'

        self.logger = getLogger()
        # is the object blacklisted?
        if IPathBlacklist(self.context).is_blacklisted():
            self.logger.warning('Could not create move job for blacklisted '+\
                                    'object (%s at %s)' % (
                    self.context.Title(),
                    '/'.join(self.context.getPhysicalPath())))
            if not no_response:
                return self.request.RESPONSE.redirect('./view')
            return False

        # This View should not be executed at the PloneSiteRoot
        if IPloneSiteRoot.providedBy(self.context):
            raise Exception('Not allowed on PloneSiteRoot')
        # get username
        user = self.context.portal_membership.getAuthenticatedMember()
        username = user.getUserName()
        # create Job
        portal = self.context.portal_url.getPortalObject()
        queue = IQueue(portal)

        additional_data = {'move_data': {
            'newName': event.newName,
            'newParent': get_site_relative_path(event.newParent),
            'newTitle': event.object.Title().decode('utf-8'),
            'oldName': event.oldName,
            'oldParent': get_site_relative_path(event.oldParent),
        }}

        queue.createJob('move', self.context, username,
                        additional_data=additional_data)
        self.logger.debug('Created "%s" Job for "%s" at %s' % (
            'move',
            self.context.Title(),
            '/'.join(self.context.getPhysicalPath()),
        ))
        # status message
        if msg is None:
            msg = _(u'Object move/rename action has been added to the queue.')

        IStatusMessage(self.request).addStatusMessage(
            msg,
            type='info'
        )
        if not no_response:
            return self.request.RESPONSE.redirect('./view')
 def get_clear_confirm_message(self):
     """Translated confirm message for clearing the queue
     """
     return self.context.translate(_(
             u'confirm_clear_queue',
             default=u'Are you sure to delete all jobs in the queue?'))
class ListExecutedJobs(PublisherConfigletView):

    COLUMNS = (('date', _(u'th_date', default=u'Date')),
               ('title', _(u'th_title', default=u'Title')),
               ('action', _(u'th_action', default=u'Action')),
               ('state', _(u'th_state', default=u'State')),
               ('username', _(u'th_username', default=u'Username')),
               ('', ''))

    actions_template = ViewPageTemplateFile('exectued_list_actions.pt')

    def __call__(self, *args,  **kwargs):
        redirect = False

        if ('button.cleanup' in self.request
            or 'button.delete.olderthan' in self.request
            or 'requeue.job' in self.request):
            redirect = self.button_action()

        if redirect:
            url = './@@publisher-config-listExecutedJobs'
            return self.request.RESPONSE.redirect(url)

        # BATCH
        # create a fake iterable object with the length of all objects,
        # but we dont want to load them all..
        fake_data = xrange(self.queue.get_executed_jobs_length())
        b_start = int(self.request.get('b_start', 0))
        self.batch = Batch(fake_data, EXECUTED_JOBS_BATCH_SIZE, b_start)

        return super(ListExecutedJobs, self).__call__(*args, **kwargs)

    @protect(PostOnly)
    @protect(CheckAuthenticator)
    def button_action(self, REQUEST=None):
        if self.request.get('button.cleanup'):
            self.queue.clear_executed_jobs()
            return True

        if self.request.get('button.delete.olderthan'):
            days = int(self.request.get('days'))
            date = datetime.datetime.now() - datetime.timedelta(days)
            self.queue.remove_executed_jobs_older_than(date)
            return True

        requeueJob = self.request.get('requeue.job')
        if requeueJob:
            key = int(requeueJob)
            try:
                job = self.queue.get_executed_job_by_key(key)
            except KeyError:
                # could not find job
                pass
            else:
                self.queue.remove_executed_job(key)
                job.move_jsonfile_to(self.config.getDataFolder())
                self.queue.appendJob(job)
                return True

    def render_table(self):
        generator = getUtility(ITableGenerator, 'ftw.tablegenerator')
        columns = [c[1] for c in ListExecutedJobs.COLUMNS]
        return generator.generate(self._get_data(), columns)

    def _get_data(self):
        columns = dict(ListExecutedJobs.COLUMNS)
        # get a batched part of the executed jobs. But we need to start
        # batching at the end, get the batch forward and then reverse,
        # because we want the newest job at the top.
        b_start = int(self.request.get('b_start', 0))
        jobs_length = self.queue.get_executed_jobs_length()
        end = jobs_length - b_start
        start = end - EXECUTED_JOBS_BATCH_SIZE
        if start < 0:
            start = 0
        entries = list(self.queue.get_executed_jobs(start, end))
        entries.reverse()
        for key, job in entries:
            state = job.get_latest_executed_entry()
            state_name = getattr(state, 'localized_name', None)
            if state_name:
                state_name = self.context.translate(state_name)
            else:
                state_name = state.__class__.__name__
            if isinstance(state, states.ErrorState):
                colored_state = '<span class="error" style="color:red;">' +\
                    '%s</span>' % self.context.translate(state_name)
            elif isinstance(state, states.WarningState):
                colored_state = '<span class="error" style="color:orange;">' +\
                    '%s</span>' % self.context.translate(state_name)
            else:
                colored_state = '<span class="success">%s</span>' % state_name
            date = 'unknown'
            try:
                date = job.executed_list[-1]['date'].strftime('%d.%m.%Y %H:%M')
            except (ConflictError, Retry):
                raise
            except:
                pass

            ctrl = self.actions_template(key=key)

            shortened_title = job.objectTitle
            maximum_length = 35

            if len(shortened_title) > maximum_length:
                try:
                    shortened_title = shortened_title.decode('utf8')
                    shortened_title = shortened_title[:maximum_length] + \
                                      u' ...'
                    shortened_title = shortened_title.encode('utf8')
                except (ConflictError, Retry):
                    raise
                except:
                    pass
            yield {
                columns['date']: date,
                columns['title']: '<a href="%s" title="%s">%s</a>' % (
                    job.objectPath + '/view',
                    job.objectTitle,
                    shortened_title),
                columns['action']: TRANSLATED_ACTIONS.get(job.action,
                                                          job.action),
                columns['state']: colored_state,
                columns['username']: job.username,
                columns['']: ctrl,
                }

    def get_translated_cleanup_prompt(self):
        """Returns the converted prompt string which is displayed when
        clicking on "cleanup".

        """
        return self.context.translate(_(
                u'prompt_cleanup',
                default=u'Are you shure to delete all executed jobs?'))
Example #32
0
class IBlacklistPathSchema(Interface):

    path = schema.TextLine(title=_(u'label_path', default=u'Path'),
                           required=True)
Example #33
0
class IEditRealmSchema(IRealmSchema):

    id = schema.TextLine(title=u'id')

    password = schema.Password(title=_(u'label_realm_password', u'Password'),
                               required=False)
 def get_clear_confirm_message(self):
     """Translated confirm message for clearing the queue
     """
     return self.context.translate(_(
             u'confirm_clear_queue',
             default=u'Are you sure to delete all jobs in the queue?'))