예제 #1
0
    async def __call__(self):
        self.interaction = IInteraction(self.request)
        definition = copy.deepcopy(
            app_settings["swagger"]["base_configuration"])
        vhm = self.request.headers.get("X-VirtualHost-Monster")
        if vhm:
            parsed_url = urlparse(vhm)
            definition["host"] = parsed_url.netloc
            definition["schemes"] = [parsed_url.scheme]
            definition["basePath"] = parsed_url.path
        else:
            definition["host"] = self.request.host
            definition["schemes"] = [get_scheme(self.request)]
        if 'version' not in definition['info']:
            definition["info"]["version"] = pkg_resources.get_distribution(
                "guillotina").version

        api_defs = app_settings["api_definition"]

        path = get_full_content_path(self.request, self.context)

        for dotted_iface in api_defs.keys():
            iface = resolve_dotted_name(dotted_iface)
            if iface.providedBy(self.context):
                iface_conf = api_defs[dotted_iface]
                self.get_endpoints(iface_conf, path, definition["paths"])

        definition["definitions"] = app_settings["json_schema_definitions"]
        return definition
예제 #2
0
async def get_all_types(context, request):
    result = []
    base_url = IAbsoluteURL(context, request)()
    constrains = IConstrainTypes(context, None)

    for id, factory in FACTORY_CACHE.items():
        add = True
        if constrains is not None:
            if not constrains.is_type_allowed(id):
                add = False

        if factory.add_permission:
            if factory.add_permission in PERMISSIONS_CACHE:
                permission = PERMISSIONS_CACHE[factory.add_permission]
            else:
                permission = query_utility(IPermission,
                                           name=factory.add_permission)
                PERMISSIONS_CACHE[factory.add_permission] = permission

            if permission is not None and \
                    not IInteraction(request).check_permission(
                        permission.id, context):
                add = False
        if add:
            result.append({
                '@id': base_url + '/@types/' + id,
                'addable': True,
                'title': id
            })
    return result
예제 #3
0
    def get_access_where_clauses(self):
        users = []
        roles = []
        request = get_current_request()
        interaction = IInteraction(request)

        for user in interaction.participations:
            users.append(user.principal.id)
            users.extend(user.principal.groups)
            roles_dict = interaction.global_principal_roles(
                user.principal.id,
                user.principal.groups)
            roles.extend([key for key, value in roles_dict.items()
                          if value])

        clauses = []
        if len(users) > 0:
            clauses.append("json->'access_users' ?| array['{}']".format(
                "','".join(users)
            ))
        if len(roles) > 0:
            clauses.append("json->'access_roles' ?| array['{}']".format(
                "','".join(roles)
            ))
        return '({})'.format(
            ' OR '.join(clauses)
        )
예제 #4
0
    async def handle_ws_request(self, ws, message):
        method = app_settings['http_methods']['GET']
        path = tuple(p for p in message['value'].split('/') if p)

        # avoid circular import
        from guillotina.traversal import do_traverse

        obj, tail = await do_traverse(self.request, self.request.container,
                                      path)

        traverse_to = None

        if tail and len(tail) == 1:
            view_name = tail[0]
        elif tail is None or len(tail) == 0:
            view_name = ''
        else:
            view_name = tail[0]
            traverse_to = tail[1:]

        permission = getUtility(IPermission, name='guillotina.AccessContent')

        allowed = IInteraction(self.request).check_permission(
            permission.id, obj)
        if not allowed:
            response = {'error': 'Not allowed'}
            ws.send_str(ujson.dumps(response))

        try:
            view = queryMultiAdapter((obj, self.request),
                                     method,
                                     name=view_name)
        except AttributeError:
            view = None

        if traverse_to is not None:
            if view is None or not ITraversableView.providedBy(view):
                response = {'error': 'Not found'}
                ws.send_str(ujson.dumps(response))
            else:
                try:
                    view = await view.publish_traverse(traverse_to)
                except Exception as e:
                    logger.error("Exception on view execution", exc_info=e)
                    response = {'error': 'Not found'}
                    ws.send_str(ujson.dumps(response))

        view_result = await view()
        if isinstance(view_result, Response):
            view_result = view_result.response

        # Return the value
        ws.send_str(ujson.dumps(view_result))

        # Wait for possible value
        futures_to_wait = self.request._futures.values()
        if futures_to_wait:
            await asyncio.gather(*list(futures_to_wait))
            self.request._futures = {}
예제 #5
0
async def create_content_in_container(parent: Folder,
                                      type_: str,
                                      id_: str,
                                      request: IRequest = None,
                                      check_security=True,
                                      **kw) -> Resource:
    """Utility to create a content.

    This method is the one to use to create content.
    id_ can be None

    :param parent: where to create content inside of
    :param type_: content type to create
    :param id_: id to give content in parent object
    :param request: <optional>
    :param check_security: be able to disable security checks
    """
    factory = get_cached_factory(type_)

    if check_security and factory.add_permission:
        if factory.add_permission in PERMISSIONS_CACHE:
            permission = PERMISSIONS_CACHE[factory.add_permission]
        else:
            permission = query_utility(IPermission,
                                       name=factory.add_permission)
            PERMISSIONS_CACHE[factory.add_permission] = permission

        if request is None:
            request = get_current_request()

        if permission is not None and \
                not IInteraction(request).check_permission(permission.id, parent):
            raise NoPermissionToAdd(str(parent), type_)

    constrains = IConstrainTypes(parent, None)
    if constrains is not None:
        if not constrains.is_type_allowed(type_):
            raise NotAllowedContentType(str(parent), type_)

    # We create the object with at least the ID
    obj = factory(id=id_, parent=parent)
    for key, value in kw.items():
        if key == 'id':
            # the factory sets id
            continue
        setattr(obj, key, value)

    txn = getattr(parent, '_p_jar', None) or get_transaction()
    if txn is None or not txn.storage.supports_unique_constraints:
        # need to manually check unique constraints
        if await parent.async_contains(obj.id):
            raise ConflictIdOnContainer(f'Duplicate ID: {parent} -> {obj.id}')

    obj.__new_marker__ = True

    await notify(BeforeObjectAddedEvent(obj, parent, id_))

    await parent.async_set(obj.id, obj)
    return obj
예제 #6
0
    async def _build_security_query(
            self,
            container,
            query,
            doc_type=None,
            size=10,
            request=None,
            scroll=None):
        if query is None:
            query = {}

        q = {}

        # The users who has plone.AccessContent permission by prinperm
        # The roles who has plone.AccessContent permission by roleperm
        users = []
        roles = []

        if request is None:
            request = get_current_request()
        interaction = IInteraction(request)

        for user in interaction.participations:  # pylint: disable=E1133
            users.append(user.principal.id)
            users.extend(user.principal.groups)
            roles_dict = interaction.global_principal_roles(
                user.principal.id,
                user.principal.groups)
            roles.extend([key for key, value in roles_dict.items()
                          if value])
        # We got all users and roles
        # users: users and groups

        should_list = [{'match': {'access_roles': x}} for x in roles]
        should_list.extend([{'match': {'access_users': x}} for x in users])

        permission_query = {
            'query': {
                'bool': {
                    'filter': {
                        'bool': {
                            'should': should_list,
                            'minimum_should_match': 1
                        }
                    }
                }
            }
        }
        query = merge_dicts(query, permission_query)
        # query.update(permission_query)
        q['body'] = query
        q['size'] = size

        if scroll:
            q['scroll'] = scroll

        logger.debug(q)
        return q
예제 #7
0
async def move(context, request):
    try:
        data = await request.json()
    except Exception:
        data = {}
    destination = data.get('destination')
    if destination is None:
        destination_ob = context.__parent__
    else:
        try:
            destination_ob = await navigate_to(request.container, destination)
        except KeyError:
            destination_ob = None

    if destination_ob is None:
        raise PreconditionFailed(context, 'Could not find destination object')
    old_id = context.id
    if 'new_id' in data:
        new_id = data['new_id']
        context.id = context.__name__ = new_id
    else:
        new_id = context.id

    security = IInteraction(request)
    if not security.check_permission('guillotina.AddContent', destination_ob):
        raise PreconditionFailed(
            context, 'You do not have permission to add content to the '
                     'destination object')

    if await destination_ob.async_contains(new_id):
        raise PreconditionFailed(
            context, f'Destination already has object with the id {new_id}')

    original_parent = context.__parent__

    txn = get_transaction(request)
    cache_keys = txn._cache.get_cache_keys(context, 'deleted')

    data['id'] = new_id
    await notify(
        BeforeObjectMovedEvent(context, original_parent, old_id, destination_ob,
                               new_id, payload=data))

    context.__parent__ = destination_ob
    context._p_register()

    await notify(
        ObjectMovedEvent(context, original_parent, old_id, destination_ob,
                         new_id, payload=data))

    cache_keys += txn._cache.get_cache_keys(context, 'added')
    await txn._cache.delete_all(cache_keys)

    absolute_url = query_multi_adapter((context, request), IAbsoluteURL)
    return {
        '@url': absolute_url()
    }
예제 #8
0
    def __init__(self,
                 utility,
                 context,
                 response=noop_response,
                 force=False,
                 log_details=False,
                 memory_tracking=False,
                 request=None,
                 bulk_size=40,
                 full=False,
                 reindex_security=False,
                 mapping_only=False):
        self.utility = utility
        self.conn = utility.conn
        self.context = context
        self.response = response
        self.force = force
        self.full = full
        self.log_details = log_details
        self.memory_tracking = memory_tracking
        self.bulk_size = bulk_size
        self.reindex_security = reindex_security
        if mapping_only and full:
            raise Exception(
                'Can not do a full reindex and a mapping only migration')
        self.mapping_only = mapping_only

        if request is None:
            self.request = get_current_request()
            self.request._db_write_enabled = False
        else:
            self.request = request
        # make sure that we don't cache requests...
        self.request._txn._cache = DummyCache(self.request._txn)
        self.container = self.request.container
        self.interaction = IInteraction(self.request)
        self.indexer = Indexer()

        self.batch = {}
        self.indexed = 0
        self.processed = 0
        self.missing = []
        self.orphaned = []
        self.existing = []
        self.errors = []
        self.mapping_diff = {}
        self.start_time = self.index_start_time = time.time()
        self.reindex_futures = []
        self.status = 'started'
        self.active_task_id = None

        self.copied_docs = 0

        self.work_index_name = None
예제 #9
0
async def resolve_uid(context, request):
    uid = request.matchdict['uid']
    ob = await get_object_by_oid(uid)
    if ob is None:
        return HTTPNotFound(content={'reason': f'Could not find uid: {uid}'})
    interaction = IInteraction(request)
    if interaction.check_permission('guillotina.AccessContent', ob):
        return HTTPMovedPermanently(get_object_url(ob, request))
    else:
        # if a user doesn't have access to it, they shouldn't know anything about it
        return HTTPNotFound(content={'reason': f'Could not find uid: {uid}'})
예제 #10
0
async def can_i_do(context, request):
    if 'permission' not in request.query and 'permissions' not in request.query:
        raise PreconditionFailed(context, 'No permission param')
    interaction = IInteraction(request)
    if 'permissions' in request.GET:
        results = {}
        for perm in request.GET['permissions'].split(','):
            results[perm] = interaction.check_permission(perm, context)
        return results
    else:
        return interaction.check_permission(request.GET['permission'], context)
예제 #11
0
        async def available_actions(self, request):
            security = IInteraction(request)
            for action_name, action in self.actions.items():
                add = False
                if 'check_permission' in action and security.check_permission(
                        action['check_permission'], self.context):
                    add = True
                elif 'check_permission' not in action:
                    add = True

                if add:
                    yield action_name, action
예제 #12
0
    async def __call__(self):
        result = {'databases': [], 'static_file': [], 'static_directory': []}
        allowed = IInteraction(self.request).check_permission(
            'guillotina.GetDatabases', self.application)

        for x in self.application._dbs.keys():
            if IDatabase.providedBy(self.application._dbs[x]) and allowed:
                result['databases'].append(x)
            if IStaticFile.providedBy(self.application._dbs[x]):
                result['static_file'].append(x)
            if IStaticDirectory.providedBy(self.application._dbs[x]):
                result['static_directory'].append(x)
        return result
예제 #13
0
    def check_permission(self, permission_name):
        if permission_name is None:
            return True

        if permission_name not in self.permission_cache:
            permission = query_utility(IPermission, name=permission_name)
            if permission is None:
                self.permission_cache[permission_name] = True
            else:
                security = IInteraction(self.request)
                self.permission_cache[permission_name] = bool(
                    security.check_permission(permission.id, self.context))
        return self.permission_cache[permission_name]
예제 #14
0
 def _invalidated_interaction_cache(self):
     # Invalidate this threads interaction cache
     try:
         request = get_current_request()
     except RequestNotFound:
         return
     interaction = IInteraction(request)
     if interaction is not None:
         try:
             invalidate_cache = interaction.invalidate_cache
         except AttributeError:
             pass
         else:
             invalidate_cache()
예제 #15
0
파일: utils.py 프로젝트: worasit/guillotina
def get_roles_with_access_content(obj, request=None):
    """ Return the roles that has access to the content that are global roles"""
    if obj is None:
        return []
    if request is None:
        request = get_current_request()
    interaction = IInteraction(request)
    roles = interaction.cached_roles(obj, 'guillotina.AccessContent', 'o')
    result = []
    all_roles = role.global_roles() + role.local_roles()
    for r in roles.keys():
        if r in all_roles:
            result.append(r)
    return result
예제 #16
0
def get_principals_with_access_content(obj, request=None):
    if obj is None:
        return {}
    if request is None:
        request = get_current_request()
    interaction = IInteraction(request)
    roles = interaction.cached_roles(obj, 'guillotina.AccessContent', 'o')
    result = []
    all_roles = role.global_roles() + role.local_roles()
    for r in roles.keys():
        if r in all_roles:
            result.append(r)
    users = interaction.cached_principals(obj, result, 'guillotina.AccessContent', 'o')
    return list(users.keys())
예제 #17
0
async def create_content_in_container(container,
                                      type_,
                                      id_,
                                      request=None,
                                      check_security=True,
                                      **kw):
    """Utility to create a content.

    This method is the one to use to create content.
    id_ can be None
    """
    factory = get_cached_factory(type_)

    if check_security and factory.add_permission:
        if factory.add_permission in PERMISSIONS_CACHE:
            permission = PERMISSIONS_CACHE[factory.add_permission]
        else:
            permission = query_utility(IPermission,
                                       name=factory.add_permission)
            PERMISSIONS_CACHE[factory.add_permission] = permission

        if request is None:
            request = get_current_request()

        if permission is not None and \
                not IInteraction(request).check_permission(permission.id, container):
            raise NoPermissionToAdd(str(container), type_)

    constrains = IConstrainTypes(container, None)
    if constrains is not None:
        if not constrains.is_type_allowed(type_):
            raise NotAllowedContentType(str(container), type_)

    # We create the object with at least the ID
    obj = factory(id=id_, parent=container)
    for key, value in kw.items():
        setattr(obj, key, value)

    txn = getattr(container, '_p_jar', None) or get_transaction()
    if txn is None or not txn.storage.supports_unique_constraints:
        # need to manually check unique constraints
        if await container.async_contains(obj.id):
            raise ConflictIdOnContainer(
                f'Duplicate ID: {container} -> {obj.id}')

    obj.__new_marker__ = True

    await notify(BeforeObjectAddedEvent(obj, container, id_))
    await container.async_set(obj.id, obj)
    return obj
예제 #18
0
async def create_content_in_container(container,
                                      type_,
                                      id_,
                                      request=None,
                                      **kw):
    """Utility to create a content.

    This method is the one to use to create content.
    id_ can be None
    """
    factory = get_cached_factory(type_)

    if factory.add_permission:
        if factory.add_permission in PERMISSIONS_CACHE:
            permission = PERMISSIONS_CACHE[factory.add_permission]
        else:
            permission = query_utility(IPermission,
                                       name=factory.add_permission)
            PERMISSIONS_CACHE[factory.add_permission] = permission

        if request is None:
            request = get_current_request()

        if permission is not None and \
                not IInteraction(request).check_permission(permission.id, container):
            raise NoPermissionToAdd(str(container), type_)

    constrains = IConstrainTypes(container, None)
    if constrains is not None:
        if not constrains.is_type_allowed(type_):
            raise NotAllowedContentType(str(container), type_)

    # We create the object with at least the ID
    obj = factory(id=id_)
    obj.__parent__ = container
    obj.__name__ = obj.id
    for key, value in kw.items():
        setattr(obj, key, value)

    if request is None or 'OVERWRITE' not in request.headers:
        if await container.async_contains(obj.id):
            raise ConflictIdOnContainer(str(container), obj.id)

    obj.__new_marker__ = True

    await notify(BeforeObjectAddedEvent(obj, container, id_))
    await container.async_set(obj.id, obj)
    return obj
예제 #19
0
    def check_permission(self, permission_name):
        if permission_name is None:
            return True

        if permission_name not in self.permission_cache:
            permission = query_utility(IPermission, name=permission_name)
            if permission is None:
                self.permission_cache[permission_name] = True
            else:
                try:
                    self.permission_cache[permission_name] = bool(
                        IInteraction(self.request).check_permission(
                            permission.id, self.context))
                except NoInteraction:
                    # not authenticated
                    return False
        return self.permission_cache[permission_name]
예제 #20
0
        async def do_action(self, request, action, comments):
            available_actions = self.actions
            if action not in available_actions:
                raise KeyError('Unavailable action')

            action_def = available_actions[action]
            security = IInteraction(request)
            if 'check_permission' in action_def and not security.check_permission(
                    action_def['check_permission'], self.context):
                raise HTTPUnauthorized()

            # Change permission
            new_state = action_def['to']

            if 'set_permission' in self.states[new_state]:
                await apply_sharing(self.context,
                                    self.states[new_state]['set_permission'])

            # Write history
            user = get_authenticated_user_id(request)
            history = {
                'actor': user,
                'comments': comments,
                'time': datetime.datetime.now(),
                'title': action_def['title'],
                'type': 'workflow',
                'data': {
                    'action': action,
                    'review_state': new_state,
                }
            }

            cms_behavior = ICMSBehavior(self.context)
            await cms_behavior.load()
            cms_behavior.review_state = new_state

            cms_behavior.history.append(history)
            cms_behavior._p_register()

            await notify(
                WorkflowChangedEvent(self.context, self, action, comments))
            return history
예제 #21
0
    async def __call__(self):
        result = await super(SerializeFolderToJson, self).__call__()

        security = IInteraction(self.request)
        length = await self.context.async_len()

        if length > MAX_ALLOWED or length == 0:
            result['items'] = []
        else:
            result['items'] = []
            async for ident, member in self.context.async_items():
                if not ident.startswith('_') and bool(
                        security.check_permission('guillotina.AccessContent',
                                                  member)):
                    result['items'].append(await getMultiAdapter(
                        (member, self.request),
                        IResourceSerializeToJsonSummary)())
        result['length'] = length

        return result
예제 #22
0
async def items(context, request):

    try:
        page_size = int(request.query['page_size'])
    except Exception:
        page_size = 20
    try:
        page = int(request.query['page'])
    except Exception:
        page = 1

    txn = get_transaction(request)

    include = omit = []
    if request.query.get('include'):
        include = request.query.get('include').split(',')
    if request.query.get('omit'):
        omit = request.query.get('omit').split(',')

    security = IInteraction(request)

    results = []
    for key in await txn.get_page_of_keys(context._p_oid,
                                          page=page,
                                          page_size=page_size):
        ob = await context.async_get(key)
        if not security.check_permission('guillotina.ViewContent', ob):
            continue
        serializer = get_multi_adapter((ob, request), IResourceSerializeToJson)
        try:
            results.append(await serializer(include=include, omit=omit))
        except TypeError:
            results.append(await serializer())

    return {
        'items': results,
        'total': await context.async_len(),
        'page': page,
        'page_size': page_size
    }
예제 #23
0
async def get_user_info(context, request):
    """Return information about the logged in user.
    """
    result = {}
    groups = set()
    principal = IInteraction(request).principal
    result[principal.id] = {
        'roles': principal.roles,
        'groups': principal.groups,
        'properties': principal.properties
    }
    groups.update(principal.groups)

    group_search = getUtility(IGroups)
    result['groups'] = {}
    for group in groups:
        group_object = group_search.get_principal(group)
        result['groups'][group_object.id] = {
            'roles': group_object.roles,
            'groups': group_object.groups
        }

    return result
예제 #24
0
async def build_security_query(container, request=None):
    # The users who has plone.AccessContent permission by prinperm
    # The roles who has plone.AccessContent permission by roleperm
    users = []
    roles = []

    if request is None:
        request = get_current_request()
    interaction = IInteraction(request)

    for user in interaction.participations:  # pylint: disable=E1133
        users.append(user.principal.id)
        users.extend(user.principal.groups)
        roles_dict = interaction.global_principal_roles(
            user.principal.id,
            user.principal.groups)
        roles.extend([key for key, value in roles_dict.items()
                      if value])
    # We got all users and roles
    # users: users and groups

    should_list = [{'match': {'access_roles': x}} for x in roles]
    should_list.extend([{'match': {'access_users': x}} for x in users])

    return {
        'query': {
            'bool': {
                'filter': {
                    'bool': {
                        'should': should_list,
                        'minimum_should_match': 1
                    }
                }
            }
        }
    }
예제 #25
0
    async def real_resolve(self, request):
        """Main function to resolve a request."""
        request._futures = {}

        security = IInteraction(request)

        method = app_settings['http_methods'][request.method]

        language = language_negotiation(request)
        language_object = language(request)

        try:
            resource, tail = await self.traverse(request)
        except ConflictError:
            # can also happen from connection errors so we bubble this...
            raise
        except Exception as _exc:
            request.resource = request.tail = None
            request.exc = _exc
            data = {
                'success': False,
                'exception_message': str(_exc),
                'exception_type': getattr(type(_exc), '__name__', str(type(_exc))),  # noqa
            }
            if app_settings.get('debug'):
                data['traceback'] = traceback.format_exc()
            # XXX should only should traceback if in some sort of dev mode?
            raise HTTPBadRequest(text=json.dumps(data))

        request.resource = resource
        request.tail = tail

        if request.resource is None:
            raise HTTPBadRequest(text='Resource not found')

        traverse_to = None
        if tail and len(tail) == 1:
            view_name = tail[0]
        elif tail is None or len(tail) == 0:
            view_name = ''
        else:
            view_name = tail[0]
            traverse_to = tail[1:]

        await self.apply_authorization(request)

        translator = queryMultiAdapter(
            (language_object, resource, request),
            ITranslated)
        if translator is not None:
            resource = translator.translate()

        # Add anonymous participation
        if len(security.participations) == 0:
            security.add(AnonymousParticipation(request))

        # container registry lookup
        try:
            view = queryMultiAdapter(
                (resource, request), method, name=view_name)
        except AttributeError:
            view = None

        request.found_view = view
        request.view_name = view_name

        # Traverse view if its needed
        if traverse_to is not None and view is not None:
            if not ITraversableView.providedBy(view):
                return None
            else:
                try:
                    view = await view.publish_traverse(traverse_to)
                except Exception as e:
                    logger.error("Exception on view execution", exc_info=e,
                                 request=request)
                    return None

        permission = getUtility(IPermission, name='guillotina.AccessContent')

        if not security.check_permission(permission.id, resource):
            # Check if its a CORS call:
            if IOPTIONS != method:
                # Check if the view has permissions explicit
                if view is None or not view.__allow_access__:
                    logger.warning("No access content {content} with {auths}".format(
                        content=resource,
                        auths=str([x.principal.id
                                   for x in security.participations])),
                        request=request)
                    raise HTTPUnauthorized()

        if view is None and method == IOPTIONS:
            view = DefaultOPTIONS(resource, request)

        if view:
            ViewClass = view.__class__
            view_permission = get_view_permission(ViewClass)
            if not security.check_permission(view_permission, view):
                logger.warning("No access for view {content} with {auths}".format(
                    content=resource,
                    auths=str([x.principal.id
                               for x in security.participations])),
                    request=request)
                raise HTTPUnauthorized()

        renderer = content_type_negotiation(request, resource, view)
        renderer_object = renderer(request)

        rendered = queryMultiAdapter(
            (renderer_object, view, request), IRendered)

        if rendered is not None:
            return MatchInfo(resource, request, view, rendered)
        else:
            return None
예제 #26
0
async def duplicate(context: IResource,
                    destination: Union[IResource, str] = None,
                    new_id: str = None,
                    check_permission: bool = True) -> IResource:
    if destination is not None:
        if isinstance(destination, str):
            request = get_current_request()
            destination_ob = await navigate_to(request.container, destination)
        else:
            destination_ob = destination

        if destination_ob is None:
            raise PreconditionFailed(
                context,
                'Could not find destination object',
            )
    else:
        destination_ob = context.__parent__

    if check_permission:
        request = get_current_request()
        security = IInteraction(request)
        if not security.check_permission('guillotina.AddContent',
                                         destination_ob):
            raise PreconditionFailed(
                context,
                'You do not have permission to add content to '
                'the destination object',
            )

    if new_id is not None:
        if await destination_ob.async_contains(new_id):
            raise PreconditionFailed(
                context,
                f'Destination already has object with the id {new_id}')
    else:
        count = 1
        new_id = f'{context.id}-duplicate-{count}'
        while await destination_ob.async_contains(new_id):
            count += 1
            new_id = f'{context.id}-duplicate-{count}'

    from guillotina.content import create_content_in_container
    new_obj = await create_content_in_container(
        destination_ob,
        context.type_name,
        new_id,
        id=new_id,
        creators=context.creators,
        contributors=context.contributors)

    for key in context.__dict__.keys():
        if key.startswith('__') or key.startswith('_BaseObject'):
            continue
        if key in ('id', ):
            continue
        new_obj.__dict__[key] = context.__dict__[key]
    new_obj.__acl__ = context.__acl__
    for behavior in context.__behaviors__:
        new_obj.add_behavior(behavior)

    # need to copy annotation data as well...
    # load all annotations for context
    [b for b in await get_all_behaviors(context, load=True)]
    annotations_container = IAnnotations(new_obj)
    for anno_id, anno_data in context.__gannotations__.items():
        new_anno_data = AnnotationData()
        for key, value in anno_data.items():
            new_anno_data[key] = value
        await annotations_container.async_set(anno_id, new_anno_data)

    await notify(
        ObjectDuplicatedEvent(new_obj,
                              context,
                              destination_ob,
                              new_id,
                              payload={
                                  'id': new_id,
                                  'destination': destination,
                              }))
    return new_obj
예제 #27
0
async def move(context: IResource,
               destination: Union[IResource, str] = None,
               new_id: str = None,
               check_permission: bool = True) -> None:
    if destination is None:
        destination_ob = context.__parent__
    else:
        if isinstance(destination, str):
            request = get_current_request()
            try:
                destination_ob = await navigate_to(request.container,
                                                   destination)
            except KeyError:
                destination_ob = None
        else:
            destination_ob = destination

    if destination_ob is None:
        raise PreconditionFailed(context, 'Could not find destination object')
    old_id = context.id
    if new_id is not None:
        context.id = context.__name__ = new_id
    else:
        new_id = context.id

    if check_permission:
        request = get_current_request()
        security = IInteraction(request)
        if not security.check_permission('guillotina.AddContent',
                                         destination_ob):
            raise PreconditionFailed(
                context, 'You do not have permission to add content to the '
                'destination object')

    if await destination_ob.async_contains(new_id):
        raise PreconditionFailed(
            context, f'Destination already has object with the id {new_id}')

    original_parent = context.__parent__

    txn = get_transaction(request)
    cache_keys = txn._cache.get_cache_keys(context, 'deleted')

    await notify(
        BeforeObjectMovedEvent(context,
                               original_parent,
                               old_id,
                               destination_ob,
                               new_id,
                               payload={
                                   'id': new_id,
                                   'destination': destination
                               }))

    context.__parent__ = destination_ob
    context._p_register()

    await notify(
        ObjectMovedEvent(context,
                         original_parent,
                         old_id,
                         destination_ob,
                         new_id,
                         payload={
                             'id': new_id,
                             'destination': destination
                         }))

    cache_keys += txn._cache.get_cache_keys(context, 'added')
    await txn._cache.delete_all(cache_keys)
예제 #28
0
async def duplicate(context, request):
    try:
        data = await request.json()
    except Exception:
        data = {}
    destination = data.get('destination')
    if destination is not None:
        destination_ob = await navigate_to(request.container, destination)
        if destination_ob is None:
            raise PreconditionFailed(
                context,
                'Could not find destination object',
            )
    else:
        destination_ob = context.__parent__

    security = IInteraction(request)
    if not security.check_permission('guillotina.AddContent', destination_ob):
        raise PreconditionFailed(
            context,
            'You do not have permission to add content to '
            'the destination object',
        )

    if 'new_id' in data:
        new_id = data['new_id']
        if await destination_ob.async_contains(new_id):
            raise PreconditionFailed(
                context,
                f'Destination already has object with the id {new_id}')
    else:
        count = 1
        new_id = f'{context.id}-duplicate-{count}'
        while await destination_ob.async_contains(new_id):
            count += 1
            new_id = f'{context.id}-duplicate-{count}'

    new_obj = await create_content_in_container(
        destination_ob,
        context.type_name,
        new_id,
        id=new_id,
        creators=context.creators,
        contributors=context.contributors)

    for key in context.__dict__.keys():
        if key.startswith('__') or key.startswith('_BaseObject'):
            continue
        if key in ('id', ):
            continue
        new_obj.__dict__[key] = context.__dict__[key]
    new_obj.__acl__ = context.__acl__
    for behavior in context.__behaviors__:
        new_obj.add_behavior(behavior)

    # need to copy annotation data as well...
    # load all annotations for context
    [b for b in await get_all_behaviors(context, load=True)]
    annotations_container = IAnnotations(new_obj)
    for anno_id, anno_data in context.__gannotations__.items():
        new_anno_data = AnnotationData()
        for key, value in anno_data.items():
            new_anno_data[key] = value
        await annotations_container.async_set(anno_id, new_anno_data)

    data['id'] = new_id
    await notify(
        ObjectDuplicatedEvent(new_obj,
                              context,
                              destination_ob,
                              new_id,
                              payload=data))

    get = DefaultGET(new_obj, request)
    return await get()
예제 #29
0
    async def __call__(self):
        ws = web.WebSocketResponse()
        await ws.prepare(self.request)

        async for msg in ws:
            if msg.tp == aiohttp.MsgType.text:
                message = ujson.loads(msg.data)
                if message['op'] == 'close':
                    await ws.close()
                elif message['op'] == 'GET':
                    method = app_settings['http_methods']['GET']
                    path = tuple(p for p in message['value'].split('/') if p)

                    # avoid circular import
                    from guillotina.traversal import do_traverse

                    obj, tail = await do_traverse(self.request,
                                                  self.request.site, path)

                    traverse_to = None

                    if tail and len(tail) == 1:
                        view_name = tail[0]
                    elif tail is None or len(tail) == 0:
                        view_name = ''
                    else:
                        view_name = tail[0]
                        traverse_to = tail[1:]

                    permission = getUtility(IPermission,
                                            name='guillotina.AccessContent')

                    allowed = IInteraction(self.request).check_permission(
                        permission.id, obj)
                    if not allowed:
                        response = {'error': 'Not allowed'}
                        ws.send_str(ujson.dumps(response))

                    try:
                        view = queryMultiAdapter((obj, self.request),
                                                 method,
                                                 name=view_name)
                    except AttributeError:
                        view = None

                    if traverse_to is not None:
                        if view is None or not ITraversableView.providedBy(
                                view):
                            response = {'error': 'Not found'}
                            ws.send_str(ujson.dumps(response))
                        else:
                            try:
                                view = await view.publish_traverse(traverse_to)
                            except Exception as e:
                                logger.error("Exception on view execution",
                                             exc_info=e)
                                response = {'error': 'Not found'}
                                ws.send_str(ujson.dumps(response))

                    view_result = await view()
                    if isinstance(view_result, Response):
                        view_result = view_result.response

                    # Return the value
                    ws.send_str(ujson.dumps(view_result))

                    # Wait for possible value
                    futures_to_wait = self.request._futures.values()
                    if futures_to_wait:
                        await asyncio.gather(futures_to_wait)
                        self.request._futures = {}
                else:
                    await ws.close()
            elif msg.tp == aiohttp.MsgType.error:
                logger.debug(
                    'ws connection closed with exception {0:s}'.format(
                        ws.exception()))

        logger.debug('websocket connection closed')

        return {}
예제 #30
0
async def can_i_do(context, request):
    if 'permission' not in request.query:
        raise TypeError('No permission param')
    permission = request.query['permission']
    return IInteraction(request).check_permission(permission, context)