示例#1
0
        def wrapped(f, *args, **kwargs):
            """The wrapped function (whose docstring will get replaced)."""
            supplied_args = _get_supplied_args(signature_params, args, kwargs)
            clashes = [s for s in supplied_args if s in exclusive_params]
            if len(clashes) > 1:
                raise InvalidParameterError(
                    'These parameters are mutually exclusive: {0}.'.format(
                        ', '.join(supplied_args))
                )

            return f(*args, **kwargs)
示例#2
0
def transition(obj=None, transition=None, to_state=None, **kwargs):
    """Perform a workflow transition for the object or attempt to perform
    workflow transitions on the object to reach the given state.
    The later will not guarantee that transition guards conditions can be met.

    Accepts kwargs to supply to the workflow policy in use, such as "comment"

    :param obj: [required] Object for which we want to perform the workflow
        transition.
    :type obj: Content object
    :param transition: Name of the workflow transition.
    :type transition: string
    :param to_state: Name of the workflow state.
    :type to_state: string
    :raises:
        :class:`~plone.api.exc.MissingParameterError`,
        :class:`~plone.api.exc.InvalidParameterError`
    :Example: :ref:`content_transition_example`
    """
    workflow = portal.get_tool('portal_workflow')
    if transition is not None:
        try:
            workflow.doActionFor(obj, transition, **kwargs)
        except WorkflowException:
            transitions = [
                action['id'] for action in workflow.listActions(object=obj)
            ]

            raise InvalidParameterError(
                "Invalid transition '{0}'.\n"
                'Valid transitions are:\n'
                '{1}'.format(transition, '\n'.join(sorted(transitions))), )
    else:
        _transition_to(obj, workflow, to_state, **kwargs)
        if workflow.getInfoFor(obj, 'review_state') != to_state:
            raise InvalidParameterError(
                'Could not find workflow to set state to {0} on {1}'.format(
                    to_state,
                    obj,
                ), )
示例#3
0
文件: env.py 项目: khink/plone.api
def adopt_roles(roles=None):
    """Context manager for temporarily switching roles.

    :param roles: New roles to gain inside block. Existing roles will be lost.
    :type roles: list of strings
    """
    if isinstance(roles, basestring):
        roles = [roles]

    if not roles:
        raise InvalidParameterError("Can't set an empty set of roles.")

    return _adopt_roles(roles)
示例#4
0
def get_registry_record(name=None):
    """Get a record value from a the ``plone.app.registry``

    :param name: [required] Name
    :type name: string
    :returns: Registry record value
    :rtype: plone.app.registry registry record
    :Example: :ref:`portal_get_registry_record_example`
    """
    if not isinstance(name, str):
        raise InvalidParameterError(u"The parameter has to be a string")

    registry = getUtility(IRegistry)
    if not name in registry:

        records = [_name for _name, record in registry.records.items()]

        raise InvalidParameterError("Cannot find a record with name '{0}'.\n"
                                    "Available records are:\n"
                                    "{1}".format(name, '\n'.join(records)))

    return registry[name]
示例#5
0
def revoke_roles(username=None, user=None, obj=None, roles=None):
    """Revoke roles from a user.

    Arguments ``username`` and ``user`` are mutually exclusive. You
    can either set one or the other, but not both. if ``username`` and
    ``user`` are not given, the authenticated member will be used.

    :param username: Username of the user that will receive the revoked roles.
    :type username: string
    :param user: User object that will receive the revoked roles.
    :type user: MemberData object
    :param obj: If obj is set then revoke roles on this context. If obj is not
        given, the site root will be used.
    :type obj: content object
    :param roles: List of roles to revoke
    :type roles: list of strings
    :raises:
        InvalidParameterError
    :Example: :ref:`user_revoke_roles_example`
    """
    if user is None:
        user = get(username=username)
    # check we got a user
    if user is None:
        raise InvalidParameterError('User could not be found')

    if isinstance(roles, tuple):
        roles = list(roles)

    if 'Anonymous' in roles or 'Authenticated' in roles:
        raise InvalidParameterError
    inherit = True
    if obj is not None:
        # if obj, get only a list of local roles, without inherited ones
        inherit = False

    actual_roles = list(get_roles(user=user, obj=obj, inherit=inherit))
    if actual_roles.count('Anonymous'):
        actual_roles.remove('Anonymous')
    if actual_roles.count('Authenticated'):
        actual_roles.remove('Authenticated')

    roles = list(set(actual_roles) - set(roles))

    if obj is None:
        user.setSecurityProfile(roles=roles)
    elif not roles:
        obj.manage_delLocalRoles([user.getId()])
    else:
        obj.manage_setLocalRoles(user.getId(), roles)
示例#6
0
def grant_roles(username=None, user=None, obj=None, roles=None):
    """Grant roles to a user.

    Arguments ``username`` and ``user`` are mutually exclusive. You
    can either set one or the other, but not both. if ``username`` and
    ``user`` are not given, the authenticated member will be used.

    :param username: Username of the user that will receive the granted roles.
    :type username: string
    :param user: User object that will receive the granted roles.
    :type user: MemberData object
    :param obj: If obj is set then grant roles on this context. If obj is not
        given, the site root will be used.
    :type obj: content object
    :param roles: List of roles to grant
    :type roles: list of strings
    :raises:
        InvalidParameterError
        MissingParameterError
    :Example: :ref:`user_grant_roles_example`
    """
    if user is None:
        user = get(username=username)
    # check we got a user
    if user is None:
        raise InvalidParameterError('User could not be found')

    if isinstance(roles, tuple):
        roles = list(roles)

    # These roles cannot be granted
    if 'Anonymous' in roles or 'Authenticated' in roles:
        raise InvalidParameterError

    if obj is None:
        actual_roles = get_roles(user=user)
    else:
        # only roles persistent on the object, not from other providers
        actual_roles = obj.get_local_roles_for_userid(username)
    roles = list(set(actual_roles) | set(roles))

    if obj is None:
        user.setSecurityProfile(roles=roles)
    else:
        obj.manage_setLocalRoles(user.getId(), roles)
示例#7
0
def set_registry_record(name=None, value=None):
    """Set a record value in the ``plone.app.registry``

    :param name: [required] Name of the record
    :type name: string
    :param value: [required] Value to set
    :type value: python primitive
    :Example: :ref:`portal_set_registry_record_example`
    """
    if not isinstance(name, str):
        raise InvalidParameterError(u"The parameter 'name' has to be a string")
    registry = getUtility(IRegistry)
    if isinstance(name, str):

        # confirm that the record exists before setting the value
        get_registry_record(name)

        registry[name] = value
示例#8
0
def get_view(name=None, context=None, request=None):
    """Get a BrowserView object.

    :param name: [required] Name of the view.
    :type name: string
    :param context: [required] Context on which to get view.
    :type context: context object
    :param request: [required] Request on which to get view.
    :type request: request object
    :raises:
        :class:`~plone.api.exc.MissingParameterError`,
        :class:`~plone.api.exc.InvalidParameterError`
    :Example: :ref:`content_get_view_example`
    """
    if not name:
        raise MissingParameterError("Missing required parameter: name")

    if not context:
        raise MissingParameterError("Missing required parameter: context")

    if not request:
        raise MissingParameterError("Missing required parameter: request")

    # It happens sometimes that ACTUAL_URL is not set in tests. To be nice
    # and not throw strange errors, we set it to be the same as URL.
    # TODO: if/when we have api.env.test_mode() boolean in the future, use that
    config = getConfiguration()
    if config.dbtab.__module__ == 'plone.testing.z2':
        request['ACTUAL_URL'] = request['URL']

    try:
        return getMultiAdapter((context, request), name=name)
    except:
        # get a list of all views so we can display their names in the error msg
        sm = getSiteManager()
        views = sm.adapters.lookupAll(required=(providedBy(context),
                                                providedBy(request)),
                                      provided=Interface)
        views_names = [view[0] for view in views]

        raise InvalidParameterError("Cannot find a view with name '%s'. \n"
                                    "Available views are:\n"
                                    "%s" %
                                    (name, '\n'.join(sorted(views_names))))
示例#9
0
def copy(source=None, target=None, id=None, safe_id=False):
    """Copy the object to the target container.

    :param source: [required] Object that we want to copy.
    :type source: Content object
    :param target: Target container to which the source object will
        be moved. If no target is specified, the source object's container will
        be used as a target.
    :type target: Folderish content object
    :param id: Id of the copied object on the target location. If no id is
        provided, the copied object will have the same id as the source object
        - however, if the new object's id conflicts with another object in the
        target container, a suffix will be added to the new object's id.
    :type id: string
    :param safe_id: When False, the given id will be enforced. If the id is
        conflicting with another object in the target container, raise a
        InvalidParameterError. When True, choose a new, non-conflicting id.
    :type safe_id: boolean
    :returns: Content object that was created in the target location
    :raises:
        KeyError,
        ValueError
    :Example: :ref:`content_copy_example`
    """
    source_id = source.getId()

    if target is None:
        target = source.aq_parent

    copy_info = target.manage_pasteObjects(
        source.aq_parent.manage_copyObjects(source_id), )

    new_id = copy_info[0]['new_id']
    if id:
        if not safe_id and id in target:
            msg = "Duplicate ID '{0}' in '{1}' for '{2}'"
            raise InvalidParameterError(msg.format(id, target, source))
        else:
            return rename(obj=target[new_id], new_id=id, safe_id=safe_id)
    else:
        return target[new_id]
示例#10
0
def get_view(name=None, context=None, request=None):
    """Get a BrowserView object.

    :param name: [required] Name of the view.
    :type name: string
    :param context: [required] Context on which to get view.
    :type context: context object
    :param request: [required] Request on which to get view.
    :type request: request object
    :raises:
        :class:`~plone.api.exc.MissingParameterError`,
        :class:`~plone.api.exc.InvalidParameterError`
    :Example: :ref:`content_get_view_example`
    """
    # We do not use exceptionhandling to detect if the requested view is
    # available, because the __init__ of said view will contain
    # errors in client code.

    # Get all available views...
    sm = getSiteManager()
    available_views = sm.adapters.lookupAll(
        required=(providedBy(context), providedBy(request)),
        provided=Interface,
    )
    # and get their names.
    available_view_names = [view[0] for view in available_views]

    # Raise an error if the requested view is not available.
    if name not in available_view_names:
        raise InvalidParameterError(
            "Cannot find a view with name '{name}'.\n"
            'Available views are:\n'
            '{views}'.format(
                name=name,
                views='\n'.join(sorted(available_view_names)),
            ), )
    return getMultiAdapter((context, request), name=name)
示例#11
0
def create(email=None,
           username=None,
           password=None,
           roles=('Member', ),
           properties=None):
    """Create a user.

    :param email: [required] Email for the new user.
    :type email: string
    :param username: Username for the new user. This is required if email
        is not used as a username.
    :type username: string
    :param password: Password for the new user. If it's not set we generate
        a random 8-char alpha-numeric one.
    :type password: string
    :param properties: User properties to assign to the new user. The list of
        available properties is available in ``portal_memberdata`` through ZMI.
    :type properties: dict
    :returns: Newly created user
    :rtype: MemberData object
    :raises:
        MissingParameterError
        InvalidParameterError
    :Example: :ref:`user_create_example`
    """
    if properties is None:
        # Never use a dict as default for a keyword argument.
        properties = {}

    # it may happen that someone passes email in the properties dict, catch
    # that and set the email so the code below this works fine
    if not email and properties.get('email'):
        email = properties.get('email')

    if not email:
        raise MissingParameterError("You need to pass the new user's email.")

    try:
        use_email_as_username = portal.get_registry_record(
            'plone.use_email_as_login')
    except InvalidParameterError:
        site = portal.get()
        props = site.portal_properties
        use_email_as_username = props.site_properties.use_email_as_login

    if not use_email_as_username and not username:
        raise InvalidParameterError(
            'The portal is configured to use username '
            'that is not email so you need to pass a username.')

    registration = portal.get_tool('portal_registration')
    user_id = use_email_as_username and email or username

    # Generate a random 8-char password
    if not password:
        chars = string.ascii_letters + string.digits
        password = ''.join(random.choice(chars) for x in range(8))

    properties.update(username=user_id)
    properties.update(email=email)

    registration.addMember(user_id, password, roles, properties=properties)
    return get(username=user_id)
示例#12
0
def create(container=None,
           type=None,
           id=None,
           title=None,
           safe_id=False,
           **kwargs):
    """Create a new content item.

    :param container: [required] Container object in which to create the new
        object.
    :type container: Folderish content object
    :param type: [required] Type of the object.
    :type type: string
    :param id: Id of the object.  If the id conflicts with another object in
        the container, a suffix will be added to the new object's id. If no id
        is provided, automatically generate one from the title. If there is no
        id or title provided, raise a ValueError.
    :type id: string
    :param title: Title of the object. If no title is provided, use id as
        the title.
    :type title: string
    :param safe_id: When False, the given id will be enforced. If the id is
        conflicting with another object in the target container, raise an
        InvalidParameterError. When True, choose a new, non-conflicting id.
    :type safe_id: boolean
    :returns: Content object
    :raises:
        KeyError,
        :class:`~plone.api.exc.MissingParameterError`,
        :class:`~plone.api.exc.InvalidParameterError`
    :Example: :ref:`content_create_example`
    """
    # Create a temporary id if the id is not given
    content_id = not safe_id and id or str(random.randint(0, 99999999))

    if title:
        kwargs['title'] = title

    try:
        container.invokeFactory(type, content_id, **kwargs)
    except UnicodeDecodeError:
        # UnicodeDecodeError is a subclass of ValueError,
        # so will be swallowed below unless we re-raise it here
        raise
    except ValueError as e:
        if ISiteRoot.providedBy(container):
            allowed_types = container.allowedContentTypes()
            types = [allowed_type.id for allowed_type in allowed_types]
        else:
            try:
                types = container.getLocallyAllowedTypes()
            except AttributeError:
                raise InvalidParameterError(
                    "Cannot add a '%s' object to the container." % type)

        raise InvalidParameterError(
            "Cannot add a '{0}' object to the container.\n"
            "Allowed types are:\n"
            "{1}\n"
            "{2}".format(type, '\n'.join(sorted(types)), e.message))

    content = container[content_id]

    # Archetypes specific code
    if IBaseObject.providedBy(content):
        # Will finish Archetypes content item creation process,
        # rename-after-creation and such
        content.processForm()

    if not id or (safe_id and id):
        # Create a new id from title
        chooser = INameChooser(container)
        derived_id = id or title
        new_id = chooser.chooseName(derived_id, content)
        # kacee: we must do a partial commit, else the renaming fails because
        # the object isn't in the zodb.
        # Thus if it is not in zodb, there's nothing to move. We should
        # choose a correct id when
        # the object is created.
        # maurits: tests run fine without this though.
        transaction.savepoint(optimistic=True)
        content.aq_parent.manage_renameObject(content_id, new_id)

    return content
示例#13
0
def get_registry_record(name=None, interface=None, default=MISSING):
    """Get a record value from ``plone.app.registry``

    :param name: [required] Name
    :type name: string
    :param interface: interface whose attributes are plone.app.registry
        settings
    :type interface: zope.interface.Interface
    :param default: The value returned if the record is not found
    :type default: anything
    :returns: Registry record value
    :rtype: plone.app.registry registry record
    :Example: :ref:`portal_get_registry_record_example`
    """
    if not isinstance(name, str):
        raise InvalidParameterError(u"The 'name' parameter has to be a string")

    if interface is not None and not IInterface.providedBy(interface):
        raise InvalidParameterError(
            u'The interface parameter has to derive from '
            u'zope.interface.Interface',
        )

    registry = getUtility(IRegistry)

    if interface is not None:
        records = registry.forInterface(interface)
        _marker = object()
        if getattr(records, name, _marker) != _marker:
            return registry['{0}.{1}'.format(interface.__identifier__, name)]

        if default is not MISSING:
            return default

        # Show all records on the interface.
        records = [key for key in interface.names()]
        msg = (
            'Cannot find a record with name "{name}"'
            ' on interface {identifier}.\n'
            'Did you mean?\n'
            '{records}'.format(
                name=name,
                identifier=interface.__identifier__,
                records='\n'.join(records),
            )
        )
        raise InvalidParameterError(msg)

    if name in registry:
        return registry[name]

    if default is not MISSING:
        return default

    # Show all records that 'look like' name.
    # We don't dump the whole list, because it 1500+ items.
    msg = (
        "Cannot find a record with name '{name}'".format(name=name)
    )
    records = [key for key in registry.records.keys() if name in key]
    if records:
        msg = (
            '{message}\n'
            'Did you mean?:\n'
            '{records}'.format(message=msg, records='\n'.join(records))
        )
    raise InvalidParameterError(msg)
示例#14
0
def transition(obj=None, transition=None, to_state=None, **kwargs):
    """Perform a workflow transition for the object or attempt to perform
    workflow transitions on the object to reach the given state.
    The later will not guarantee that transition guards conditions can be met.

    Accepts kwargs to supply to the workflow policy in use, such as "comment"

    :param obj: [required] Object for which we want to perform the workflow
        transition.
    :type obj: Content object
    :param transition: Name of the workflow transition.
    :type transition: string
    :param to_state: Name of the workflow state.
    :type to_state: string
    :raises:
        :class:`~plone.api.exc.MissingParameterError`,
        :class:`~plone.api.exc.InvalidParameterError`
    :Example: :ref:`content_transition_example`
    """
    workflow = portal.get_tool('portal_workflow')
    if transition is not None:
        try:
            workflow.doActionFor(obj, transition, **kwargs)
        except WorkflowException:
            transitions = [
                action['id'] for action in workflow.listActions(object=obj)
            ]

            raise InvalidParameterError(
                "Invalid transition '{0}'.\n"
                'Valid transitions are:\n'
                '{1}'.format(transition, '\n'.join(sorted(transitions)))
            )
    else:
        # move from the current state to the given state
        # via any route we can find
        for wf in workflow.getWorkflowsFor(obj):
            status = workflow.getStatusOf(wf.getId(), obj)
            if not status or not status.get('review_state'):
                continue
            if status['review_state'] == to_state:
                return

            transitions = _wf_transitions_for(
                wf,
                status['review_state'],
                to_state,
            )
            if not transitions:
                continue

            for transition in transitions:
                try:
                    workflow.doActionFor(obj, transition, **kwargs)
                except WorkflowException:
                    # take into account automatic transitions.
                    # If the transitions list that are being iterated over
                    # have automatic transitions they need to be skipped
                    if get_state(obj) == to_state:
                        break

            break

        if workflow.getInfoFor(obj, 'review_state') != to_state:
            raise InvalidParameterError(
                'Could not find workflow to set state to {0} on {1}'.format(
                    to_state,
                    obj,
                )
            )