Ejemplo n.º 1
0
    def __call__(self, id, processing, *args, **kwargs):

        # Get the requested element
        item = resolve_object_ref(Item, id)

        # Make sure the selected element exists
        if item is None:
            raise cherrypy.NotFound()

        # Normalize the URL to use a local id
        if id == item.global_id:
            raise cherrypy.HTTPRedirect(cherrypy.url().replace(
                "/" + id + "/", "/%d/" % item.id))

        # Handle legacy image requests (woost < 0.8)
        if args or kwargs or "(" in processing:
            raise cherrypy.HTTPError(410)

        # Parse the given processing string, splitting the image factory from
        # the image format (ie. "home_thumbnail.png" -> ("home_thumbnail", "PNG"))
        parts = processing.rsplit(".", 1)
        parameters = None

        if len(parts) == 2:
            factory_id, ext = parts
            format = formats_by_extension.get(ext)
            if format is None:
                raise cherrypy.HTTPError(400,
                                         "Invalid image extension: %s" % ext)
        else:
            factory_id = processing
            format = None

        factory = ImageFactory.get_instance(identifier=factory_id)

        if factory is None:
            match = generic_image_factory_pattern.match(factory_id)
            if match:
                try:
                    factory_id = int(match.group(1))
                    factory = ImageFactory.require_instance(factory_id)
                except:
                    pass

            if factory is None:
                raise cherrypy.HTTPError(
                    400, "Invalid image factory id: %s" % factory_id)

        # Deny access to unauthorized elements
        get_current_user().require_permission(RenderPermission,
                                              target=item,
                                              image_factory=factory)

        try:
            image_cache_file = require_rendering(item, factory, format,
                                                 parameters)
        except BadRenderingRequest, ex:
            raise cherrypy.HTTPError(400, ex.message)
Ejemplo n.º 2
0
    def handle_traversed(cls, event):

        controller = event.source

        # Require an edit stack with an edit node on top
        controller._require_edit_node()

        # Disable access to invisible content types
        if not controller.stack_node.content_type.visible:
            raise cherrypy.NotFound()

        # Restrict access
        if controller.stack_node.item.is_inserted:
            get_current_user().require_permission(
                ReadPermission, target=controller.stack_node.item)
Ejemplo n.º 3
0
    def submit(self):

        collection = self.collection
        selection = self.selection
        parent = self.item
        position = self.position
        related_end = self.member.related_end

        size = len(collection)

        if position < 0:
            position = size + position

        position = min(position, size)

        if any(parent.descends_from(item) for item in selection):
            raise TreeCycleError()

        for i in range(self.MAX_TRANSACTION_ATTEMPTS):
            with changeset_context(get_current_user()):
                for item in reversed(selection):

                    if isinstance(related_end, Reference) \
                    and item.get(related_end) is parent:
                        collection.remove(item)

                    collection.insert(position, item)            
            try:
                datastore.commit()
            except ConflictError:
                datastore.abort()
                datastore.sync()
            else:
                break
Ejemplo n.º 4
0
    def user_collection(self):

        class ChangeLogUserCollection(BackOfficeUserCollection):
            persistence_prefix = "changelog"
            schema = self.content_schema
            default_order = [NegativeExpression(ChangeSet.id)]
            allow_sorting = False
            allow_type_selection = False
            allow_language_selection = False
            available_languages = Configuration.instance.languages

            @cached_getter
            def available_user_filters(self):
                filters = BackOfficeUserCollection.available_user_filters(self)
                cs_action_filter = ChangeSetActionFilter()
                cs_action_filter.id = "member-action"
                cs_target_filter = ChangeSetTargetFilter()
                cs_target_filter.id = "member-changes"
                filters.append(cs_action_filter)
                filters.append(cs_target_filter)
                return filters

        user_collection = ChangeLogUserCollection(ChangeSet)
        user_collection.params.source = SessionParameterSource(
            key_prefix = user_collection.persistence_prefix
        )
        user_collection.add_base_filter(
            ChangeSetPermissionExpression(get_current_user())
        )
        return user_collection
Ejemplo n.º 5
0
        def submit(self):
            document = self.controller.context["publishable"]

            # Write to the database
            if document.should_save_instances:
                with changeset_context(get_current_user()):
                    UploadForm.submit(self)
                    self.instance.insert()
                datastore.commit()

            # Do not write to the database, only process form data
            else:
                UploadForm.submit(self)

            # Send email messages based on the submitted data
            for email_template in document.email_notifications:
                email_template.send({
                    "form": document,
                    "instance": self.instance
                })

            # Redirect the user to a confirmation page
            if document.redirection:
                raise cherrypy.HTTPRedirect(self.controller.context["cms"].uri(
                    document.redirection,
                    form=document.id,
                    instance=None if not document.should_save_instances else
                    self.instance.id))
Ejemplo n.º 6
0
    def mailing_state(self, task_id, *args, **kwargs):
        cherrypy.response.headers["Content-Type"] = "application/json"

        task = tasks.get(int(task_id))

        # If task is expired show the status from the mailing object
        if task is None:
            mailing = self.context["cms_item"]
        else:
            mailing = Mailing.get_instance(task.mailing_id)

        if mailing is None:
            return dumps({})

        user = get_current_user()
        if not user.has_permission(ReadPermission, target = mailing):
            raise cherrypy.HTTPError(403, "Forbidden")

        tasks.remove_expired_tasks()

        return dumps({
            "sent": len(mailing.sent),
            "errors": len(mailing.errors),
            "total": mailing.total,
            "completed": task and task.completed or True
        })
Ejemplo n.º 7
0
    def export_form_data(self, item, form_data):
        """Update the edit form with the data contained on the edited item."""

        self.form_adapter.export_object(item, form_data, self.content_type,
                                        self.form_schema)

        # Default translations
        if self.content_type.translated:

            user = get_current_user()
            available_languages = set(
                language for language in item.translations
                if user.has_permission(ReadTranslationPermission,
                                       language=language))

            if not self._item.translations:
                default_language = \
                    Configuration.instance.get_setting("default_language")
                if default_language in available_languages:
                    self._item.new_translation(default_language)

            self.translations = [
                language for language in self._item.translations.keys()
                if language in available_languages
            ]
        else:
            self.translations = []
Ejemplo n.º 8
0
    def submit(self):

        from woost.extensions.campaignmonitor import CampaignMonitorExtension
        extension = CampaignMonitorExtension.instance
        user = get_current_user()

        with changeset_context(author=user) as changeset:
            extension.synchronize_lists(restricted=True)

            # Report changed lists
            created = set()
            modified = set()
            deleted = set()

            for change in changeset.changes.itervalues():

                if isinstance(change.target, CampaignMonitorList):
                    action_id = change.action.identifier

                    if action_id == "create":
                        created.add(change.target)
                    elif action_id == "modify":
                        modified.add(change.target)
                    elif action_id == "delete":
                        deleted.add(change.target)

        datastore.commit()

        self.output["created_lists"] = created
        self.output["modified_lists"] = modified
        self.output["deleted_lists"] = deleted
Ejemplo n.º 9
0
 def handle_producing_output(cls, event):
     # Set application wide output parameters
     cms = event.source
     event.output.update(
         cms=cms,
         user=get_current_user(),
         publishable=event.controller.context.get("publishable"))
Ejemplo n.º 10
0
def breakpoint(open_browser=False, stack_depth=0):
    """Set a `~webconsole.utils.breakpoint` that is only triggered by users
    with `code execution rights <WebConsolePermission>`.
    """
    from cocktail.controllers import Location
    from webconsole.utils import breakpoint as webconsole_breakpoint
    from woost.models import get_current_user, Publishable
    from woost.extensions.webconsole.webconsolepermission \
        import WebConsolePermission

    user = get_current_user()

    if user and user.has_permission(WebConsolePermission):

        def initializer(session):
            if open_browser:

                # Find the web console document
                webconsole = Publishable.require_instance(
                    qname="woost.extensions.webconsole.page")

                # Determine the URI for the breakpoint session
                webconsole_location = Location.get_current_host()
                webconsole_location.path_info = webconsole.get_uri()
                webconsole_location.query_string["session_id"] = session.id

                # Open a web browser tab pointing at the URI
                from webbrowser import open
                open(str(webconsole_location))

        return webconsole_breakpoint(initializer=initializer,
                                     stack_depth=stack_depth + 1)
Ejemplo n.º 11
0
 def get_options(cls):
     for member in cls.members().itervalues():
         if (member is not cls.product and member is not cls.order
                 and member.visible and member.editable
                 and issubclass(member.schema, ECommercePurchase)
                 and get_current_user().has_permission(
                     ModifyMemberPermission, member=member)):
             yield member
Ejemplo n.º 12
0
    def form_errors(self):
        form_errors = FormControllerMixin.form_errors(self)

        if not form_errors and self.submitted and get_current_user().anonymous:
            user_param = get_parameter(schema.Member("user"))
            form_errors._items.append(AuthenticationFailedError(user_param))

        return form_errors
Ejemplo n.º 13
0
 def available_languages(self):
     user = get_current_user()
     return [language
             for language in Configuration.instance.languages
             if user.has_permission(
                 ReadTranslationPermission,
                 language = language
             )]
Ejemplo n.º 14
0
    def user_views(self):

        user = get_current_user()
        views = OrderedSet()

        for role in user.iter_roles():
            views.extend(role.user_views)

        return views
 def allowed_destinations():
     return [
         destination 
         for destination in extension.destinations 
         if get_current_user().has_permission(
             ExportationPermission,
             destination = destination
         )
     ]
Ejemplo n.º 16
0
 def current_user(self):
     cherrypy.response.headers["Content-Type"] = "text/javascript"
     user = get_current_user()
     return "cocktail.declare('woost'); woost.user = %s;" % dumps(
         {
             "id": user.id,
             "label": translations(user),
             "identifier": user.get(app.authentication.identifier_field),
             "anonymous": user.anonymous
         } if user else None)
Ejemplo n.º 17
0
    def validate_publishable(self, publishable):

        if not publishable.is_published():
            raise cherrypy.NotFound()

        user = get_current_user()

        user.require_permission(ReadPermission, target=publishable)
        user.require_permission(ReadTranslationPermission,
                                language=get_language())
Ejemplo n.º 18
0
    def handle_traversed(cls, event):

        # Restrict access to the edited item
        controller = event.source
        item = controller.stack_node.item
        user = get_current_user()

        if item.is_inserted:
            user.require_permission(ModifyPermission, target=item)
        else:
            user.require_permission(CreatePermission, target=item.__class__)
Ejemplo n.º 19
0
 def adapter(self):
     """The schema adapter used to produce data suitable for listing.
     @type: L{SchemaAdapter<cocktail.schema.adapter.SchemaAdapter>}
     """
     user = get_current_user()
     adapter = schema.Adapter()
     adapter.exclude([
         member.name for member in self.type.members().itervalues()
         if not member.visible
         or not user.has_permission(ReadMemberPermission, member=member)
     ])
     return adapter
Ejemplo n.º 20
0
    def available_languages(self):
        """The list of languages that items in the listing can be displayed in.

        Each language is represented using its two letter ISO code.

        @type: sequence of unicode
        """
        user = get_current_user()
        return [
            language for language in Configuration.instance.languages
            if user.has_permission(ReadTranslationPermission,
                                   language=language)
        ]
Ejemplo n.º 21
0
    def _delete_instances(self, query):

        user = get_current_user()

        class ValidatingDeletedSet(InstrumentedSet):
            def item_added(self, item):
                user.require_permission(DeletePermission, target=item)

        deleted_set = ValidatingDeletedSet()

        with changeset_context(user):
            for item in list(query):
                item.delete(deleted_set)
Ejemplo n.º 22
0
    def __call__(self, *args, **kwargs):

        node = self.stack_node
        previewed_item = self.previewed_item
        publishable = self.preview_publishable
        preview_language = self.preview_language
        user = get_current_user()

        # Set the language for the preview
        if preview_language:
            set_language(preview_language)

        # Enforce permissions
        user.require_permission(ReadPermission, target=previewed_item)

        if publishable is not previewed_item:
            user.require_permission(ReadPermission, target=publishable)

        # Disable the preview if the item's unsaved state produces validation
        # errors; these would usually lead to unhandled server errors during
        # rendering.
        errors = schema.ErrorList(node.iter_errors())

        if errors:
            error_box = templates.new("cocktail.html.ErrorBox")
            error_box.errors = errors
            message = Element("div",
                              class_name="preview-error-box",
                              children=[
                                  translations(
                                      "woost.backoffice invalid item preview",
                                      preview_language), error_box
                              ])
            message.add_resource("/resources/styles/backoffice.css")
            return message.render_page()

        # Update the edited item with the data to preview
        node.import_form_data(node.form_data, previewed_item)

        self.context.update(original_publishable=self.context["publishable"],
                            publishable=publishable)

        controller = publishable.resolve_controller()

        if controller is None:
            raise cherrypy.NotFound()

        if isinstance(controller, type):
            controller = controller()

        return controller()
Ejemplo n.º 23
0
    def _apply_https_policy(self, publishable):

        policy = Configuration.instance.get_setting("https_policy")
        website = get_current_website()

        if policy == "always":
            Location.require_https()
        elif policy == "never":
            Location.require_http()
        elif policy == "per_page":
            if publishable.requires_https or not get_current_user().anonymous:
                Location.require_https()
            elif not website.https_persistence:
                Location.require_http()
Ejemplo n.º 24
0
    def get_error_page(self, error):
        """Produces a custom error page for the indicated exception.

        @param error: The exception to describe.
        @type error: Exception

        @return: A tuple comprised of a publishable item to delegate to and an
            HTTP status to set on the response. Either component can be None,
            so that no custom error page is shown, or that the status is not
            changed, respectively.
        @rtype: (L{Document<woost.models.Document>}, int)
        """
        is_http_error = isinstance(error, cherrypy.HTTPError)
        config = Configuration.instance
        page = None
        page_name = None
        status = None

        # Page not found
        if is_http_error and error.status == 404:
            return config.get_setting("not_found_error_page"), 404

        # Service unavailable
        elif is_http_error and error.status == 503:
            return config.get_setting("maintenance_page"), 503

        # Access forbidden:
        # The default behavior is to show a login page for anonymous users, and
        # a 403 error message for authenticated users.
        elif ((is_http_error and error.status == 403)
              or isinstance(error,
                            (AuthorizationError, AuthenticationFailedError))):
            if get_current_user().anonymous:
                publishable = self.context["publishable"]

                while publishable is not None:
                    login_page = publishable.login_page
                    if login_page is not None:
                        return login_page, 403
                    publishable = publishable.parent

                return config.get_setting("login_page"), 403
            else:
                return config.get_setting("forbidden_error_page"), 403

        # Generic error
        elif (is_http_error and error.status == 500) or not is_http_error:
            return config.get_setting("generic_error_page"), 500

        return None, None
Ejemplo n.º 25
0
    def get_public_adapter(cls):
        from woost.extensions.ecommerce import ECommerceExtension

        user = get_current_user()
        adapter = schema.Adapter()
        adapter.exclude(["customer", "status", "purchases"])
        adapter.exclude([
            member.name for member in cls.members().itervalues()
            if not member.visible or not member.editable
            or not issubclass(member.schema, ECommerceOrder)
            or not user.has_permission(ModifyMemberPermission, member=member)
        ])
        if len(ECommerceExtension.instance.payment_types) == 1:
            adapter.exclude(["payment_type"])
        return adapter
Ejemplo n.º 26
0
    def session(self):

        session = WebConsoleController.session(self)

        session.context.update(config=Configuration.instance,
                               user=get_current_user(),
                               language=get_language(),
                               translations=translations,
                               first=first,
                               last=last)

        for model in PersistentObject.schema_tree():
            session.context[model.name] = model

        return session
Ejemplo n.º 27
0
    def allowed_publication_targets(self):

        from woost.extensions.facebookpublication \
            import FacebookPublicationExtension

        user = get_current_user()

        return [
            fb_target
            for fb_target in FacebookPublicationExtension.instance.targets
            if fb_target.auth_token and all(
                user.has_permission(FacebookPublicationPermission,
                                    target=publishable,
                                    publication_target=fb_target)
                for publishable in self.selection)
        ]
Ejemplo n.º 28
0
    def _fill_entries(self):

        user = get_current_user()
        items = self.items

        if items is not None:
            items = [
                item for item in self.items
                if user.has_permission(ReadPermission, target=item)
            ]

        if items:
            List._fill_entries(self)
        else:
            self.tag = "div"
            self.append(u"-")
Ejemplo n.º 29
0
    def create_new_button(self):

        new_button = Element(class_name="ItemSelector-button new")

        instantiable_types = set(
            content_type
            for content_type in ([self.member.type] +
                                 list(self.member.type.derived_schemas()))
            if content_type.visible and content_type.instantiable
            and get_current_user().has_permission(CreatePermission,
                                                  target=content_type))

        if len(instantiable_types) > 1:

            new_button.add_class("selector")
            label = Element("span", class_name="label")
            new_button.append(label)

            container = Element(class_name="selector_content")
            new_button.append(container)

            content_type_tree = templates.new("woost.views.ContentTypeTree")
            content_type_tree.root = self.member.type
            content_type_tree.filter_item = instantiable_types.__contains__

            @extend(content_type_tree)
            def create_label(tree, content_type):
                label = call_base(content_type)
                label.tag = "button"
                label["type"] = "submit"
                label["name"] = "relation-new"
                label[
                    "value"] = self.member.name + "-" + content_type.full_name
                return label

            container.append(content_type_tree)
        else:
            new_button.tag = "button"
            new_button["type"] = "submit"
            new_button["name"] = "relation-new"
            new_button["value"] = \
                self.member.name + "-" + list(instantiable_types)[0].full_name
            label = new_button

        label.append(translations("woost.views.ItemSelector new"))

        return new_button
Ejemplo n.º 30
0
    def _export(self, context, status_tracker=None):
        StaticSiteDestination._export(self,
                                      context,
                                      status_tracker=status_tracker)

        # Close the zip file before export it to the CMS
        context["zip_file"].close()
        upload_path = app.path("upload")

        with changeset_context(get_current_user()):
            file = File.from_path(context["temp_file"],
                                  upload_path,
                                  languages=[get_language()])
            file.title = "export-%s" % date.today().strftime("%Y%m%d")
            file.file_name = file.title + ".zip"
            file.insert()
            context.update(file=file)