Ejemplo n.º 1
0
def s3_rest_controller(prefix=None, resourcename=None, **attr):
    """
        Helper function to apply the S3Resource REST interface

        @param prefix: the application prefix
        @param resourcename: the resource name (without prefix)
        @param attr: additional keyword parameters

        Any keyword parameters will be copied into the output dict (provided
        that the output is a dict). If a keyword parameter is callable, then
        it will be invoked, and its return value will be added to the output
        dict instead. The callable receives the S3Request as its first and
        only parameter.

        CRUD can be configured per table using:

            s3db.configure(tablename, **attr)

        *** Redirection:

        create_next             URL to redirect to after a record has been created
        update_next             URL to redirect to after a record has been updated
        delete_next             URL to redirect to after a record has been deleted

        *** Form configuration:

        list_fields             list of names of fields to include into list views
        subheadings             Sub-headings (see separate documentation)
        listadd                 Enable/Disable add-form in list views

        *** CRUD configuration:

        editable                Allow/Deny record updates in this table
        deletable               Allow/Deny record deletions in this table
        insertable              Allow/Deny record insertions into this table
        copyable                Allow/Deny record copying within this table

        *** Callbacks:

        create_onvalidation     Function for additional record validation on create
        create_onaccept         Function after successful record insertion

        update_onvalidation     Function for additional record validation on update
        update_onaccept         Function after successful record update

        onvalidation            Fallback for both create_onvalidation and update_onvalidation
        onaccept                Fallback for both create_onaccept and update_onaccept
        ondelete                Function after record deletion
    """

    # Customise Controller from Template
    attr = settings.customise_controller(
        "%s_%s" %
        (prefix or request.controller, resourcename or request.function),
        **attr)

    # Parse the request
    r = s3_request(prefix, resourcename)

    # Customize target resource(s) from Template
    r.customise_resource()

    # Configure standard method handlers
    set_handler = r.set_handler
    set_handler("barchart", s3_barchart)
    from s3db.cms import S3CMS
    set_handler("cms", S3CMS)
    set_handler("compose", s3base.S3Compose)
    # @ToDo: Make work in Component Tabs:
    set_handler("copy", lambda r, **attr: \
                               redirect(URL(args="create",
                                            vars={"from_record":r.id})))
    set_handler("deduplicate", s3base.S3Merge)
    set_handler("filter", s3base.S3Filter)
    set_handler("import", s3base.S3Importer)
    set_handler("map", s3base.S3Map)
    set_handler("profile", s3base.S3Profile)
    set_handler("report", s3base.S3Report)
    set_handler("timeplot", s3base.S3TimePlot)  # temporary setting for testing
    set_handler("search_ac", s3base.search_ac)
    set_handler("summary", s3base.S3Summary)

    # Don't load S3PDF unless needed (very slow import with Reportlab)
    method = r.method
    if method == "import" and r.representation == "pdf":
        from s3.s3pdf import S3PDF
        set_handler("import",
                    S3PDF(),
                    http=["GET", "POST"],
                    representation="pdf")

    # Plugin OrgRoleManager where appropriate
    if r.record and auth.user is not None and \
       r.tablename in s3base.S3OrgRoleManager.ENTITY_TYPES:

        sr = auth.get_system_roles()
        realms = auth.user.realms or Storage()

        if sr.ADMIN in realms or sr.ORG_ADMIN in realms and \
           (realms[sr.ORG_ADMIN] is None or \
            r.record.pe_id in realms[sr.ORG_ADMIN]):
            r.set_handler("roles", s3base.S3OrgRoleManager())

    # Execute the request
    output = r(**attr)

    if isinstance(output, dict) and \
       method in (None,
                  "report",
                  "search",
                  "datatable",
                  "datatable_f",
                  "summary"):

        if s3.actions is None:

            # Add default action buttons
            prefix, name, table, tablename = r.target()
            authorised = s3_has_permission("update", tablename)

            # If a component has components itself, then action buttons
            # can be forwarded to the native controller by setting native=True
            if r.component and s3db.has_components(table):
                native = output.get("native", False)
            else:
                native = False

            # Get table config
            get_config = s3db.get_config
            listadd = get_config(tablename, "listadd", True)
            editable = get_config(tablename, "editable", True) and \
                       not auth.permission.ownership_required("update", table)
            deletable = get_config(tablename, "deletable", True)
            copyable = get_config(tablename, "copyable", False)

            # URL to open the resource
            open_url = r.resource.crud._linkto(r,
                                               authorised=authorised,
                                               update=editable,
                                               native=native)("[id]")

            # Add action buttons for Open/Delete/Copy as appropriate
            s3_action_buttons(
                r,
                deletable=deletable,
                copyable=copyable,
                editable=editable,
                read_url=open_url,
                update_url=open_url
                # To use modals
                #update_url="%s.popup?refresh=list" % open_url
            )

            # Override Add-button, link to native controller and put
            # the primary key into vars for automatic linking
            if native and not listadd and \
               s3_has_permission("create", tablename):
                label = s3base.S3CRUD.crud_string(tablename, "label_create")
                hook = r.resource.components[name]
                fkey = "%s.%s" % (name, hook.fkey)
                vars = request.vars.copy()
                vars.update({fkey: r.record[hook.fkey]})
                url = URL(prefix, name, args=["create"], vars=vars)
                add_btn = A(label, _href=url, _class="action-btn")
                output.update(add_btn=add_btn)

    elif method not in ("import", "review", "approve", "reject",
                        "deduplicate"):
        s3.actions = None

    output = s3_guided_tour(output)

    return output
Ejemplo n.º 2
0
def s3_rest_controller(prefix=None, resourcename=None, **attr):
    """
        Helper function to apply the S3Resource REST interface

        @param prefix: the application prefix
        @param resourcename: the resource name (without prefix)
        @param attr: additional keyword parameters

        Any keyword parameters will be copied into the output dict (provided
        that the output is a dict). If a keyword parameter is callable, then
        it will be invoked, and its return value will be added to the output
        dict instead. The callable receives the S3Request as its first and
        only parameter.

        CRUD can be configured per table using:

            s3db.configure(tablename, **attr)

        *** Redirection:

        create_next             URL to redirect to after a record has been created
        update_next             URL to redirect to after a record has been updated
        delete_next             URL to redirect to after a record has been deleted

        *** Form configuration:

        list_fields             list of names of fields to include into list views
        subheadings             Sub-headings (see separate documentation)
        listadd                 Enable/Disable add-form in list views

        *** CRUD configuration:

        editable                Allow/Deny record updates in this table
        deletable               Allow/Deny record deletions in this table
        insertable              Allow/Deny record insertions into this table
        copyable                Allow/Deny record copying within this table

        *** Callbacks:

        create_onvalidation     Function/Lambda for additional record validation on create
        create_onaccept         Function/Lambda after successful record insertion

        update_onvalidation     Function/Lambda for additional record validation on update
        update_onaccept         Function/Lambda after successful record update

        onvalidation            Fallback for both create_onvalidation and update_onvalidation
        onaccept                Fallback for both create_onaccept and update_onaccept
        ondelete                Function/Lambda after record deletion
    """

    # Parse the request
    r = s3mgr.parse_request(prefix, resourcename)

    # Set method handlers
    r.set_handler("barchart", s3_barchart)
    r.set_handler("compose", s3base.S3Compose())
    r.set_handler("copy", s3_copy)
    r.set_handler("report", s3base.S3Cube())
    r.set_handler("import", s3base.S3Importer())
    r.set_handler("map", s3base.S3Map())

    # Activate record approval?
    if deployment_settings.get_auth_record_approval():
        prefix, name, table, tablename = r.target()
        if "approved_by" in table.fields and \
           s3db.get_config(tablename, "requires_approval", False):
            r.set_handler(["approve", "reject"],
                          s3base.S3ApproveRecords(),
                          http=["GET", "POST"])

    # Don't load S3PDF unless needed (very slow import with reportlab)
    if r.method == "import" and r.representation == "pdf":
        from s3.s3pdf import S3PDF
        r.set_handler("import",
                      S3PDF(),
                      http=["GET", "POST"],
                      representation="pdf")

    # Execute the request
    output = r(**attr)

    if isinstance(output, dict) and (not r.method
                                     or r.method in ("report", "search")):
        if s3.actions is None:

            # Add default action buttons
            prefix, name, table, tablename = r.target()
            authorised = s3_has_permission("update", tablename)

            # If the component has components itself, then use the
            # component's native controller for CRU(D) => make sure
            # you have one, or override by native=False
            if r.component and s3db.has_components(table):
                native = output.get("native", True)
            else:
                native = False

            # Get table config
            get_config = s3db.get_config
            listadd = get_config(tablename, "listadd", True)
            editable = get_config(tablename, "editable", True) and \
                       not auth.permission.ownership_required("update", table)
            deletable = get_config(tablename, "deletable", True)
            copyable = get_config(tablename, "copyable", False)

            # URL to open the resource
            open_url = r.resource.crud._linkto(r,
                                               authorised=authorised,
                                               update=editable,
                                               native=native)("[id]")

            # Add action buttons for Open/Delete/Copy as appropriate
            s3_action_buttons(r,
                              deletable=deletable,
                              copyable=copyable,
                              editable=editable,
                              read_url=open_url,
                              update_url=open_url)

            # Override Add-button, link to native controller and put
            # the primary key into vars for automatic linking
            if native and not listadd and \
               s3_has_permission("create", tablename):
                label = s3base.S3CRUD.crud_string(tablename,
                                                  "label_create_button")
                hook = r.resource.components[name]
                fkey = "%s.%s" % (name, hook.fkey)
                vars = request.vars.copy()
                vars.update({fkey: r.id})
                url = URL(prefix, name, args=["create"], vars=vars)
                add_btn = A(label, _href=url, _class="action-btn")
                output.update(add_btn=add_btn)

    elif r.method not in ("import", "approve", "reject"):
        s3.actions = None

    return output
Ejemplo n.º 3
0
def s3_rest_controller(prefix=None, resourcename=None, **attr):
    """
        Helper function to apply the S3Resource REST interface

        @param prefix: the application prefix
        @param resourcename: the resource name (without prefix)
        @param attr: additional keyword parameters

        Any keyword parameters will be copied into the output dict (provided
        that the output is a dict). If a keyword parameter is callable, then
        it will be invoked, and its return value will be added to the output
        dict instead. The callable receives the S3Request as its first and
        only parameter.

        CRUD can be configured per table using:

            s3db.configure(tablename, **attr)

        *** Redirection:

        create_next             URL to redirect to after a record has been created
        update_next             URL to redirect to after a record has been updated
        delete_next             URL to redirect to after a record has been deleted

        *** Form configuration:

        list_fields             list of names of fields to include into list views
        subheadings             Sub-headings (see separate documentation)
        listadd                 Enable/Disable add-form in list views

        *** CRUD configuration:

        editable                Allow/Deny record updates in this table
        deletable               Allow/Deny record deletions in this table
        insertable              Allow/Deny record insertions into this table
        copyable                Allow/Deny record copying within this table

        *** Callbacks:

        create_onvalidation     Function for additional record validation on create
        create_onaccept         Function after successful record insertion

        update_onvalidation     Function for additional record validation on update
        update_onaccept         Function after successful record update

        onvalidation            Fallback for both create_onvalidation and update_onvalidation
        onaccept                Fallback for both create_onaccept and update_onaccept
        ondelete                Function after record deletion
    """

    # Parse the request
    dynamic = attr.get("dynamic")
    if dynamic:
        # Dynamic table controller
        c = request.controller
        f = request.function
        attr = settings.customise_controller("%s_%s" % (c, f), **attr)
        from s3 import DYNAMIC_PREFIX, s3_get_extension
        r = s3_request(DYNAMIC_PREFIX,
                       dynamic,
                       f = "%s/%s" % (f, dynamic),
                       args = request.args[1:],
                       extension = s3_get_extension(request),
                       )
    else:
        # Customise Controller from Template
        attr = settings.customise_controller(
                    "%s_%s" % (prefix or request.controller,
                               resourcename or request.function,
                               ),
                    **attr)
        r = s3_request(prefix, resourcename)

    # Customize target resource(s) from Template
    r.customise_resource()

    # Configure standard method handlers
    set_handler = r.set_handler
    from s3db.cms import S3CMS
    set_handler("cms", S3CMS)
    set_handler("compose", s3base.S3Compose)
    # @ToDo: Make work in Component Tabs:
    set_handler("copy", lambda r, **attr: \
                               redirect(URL(args="create",
                                            vars={"from_record":r.id})))
    set_handler("deduplicate", s3base.S3Merge)
    set_handler("filter", s3base.S3Filter)
    set_handler("grouped", s3base.S3GroupedItemsReport)
    set_handler("hierarchy", s3base.S3HierarchyCRUD)
    set_handler("import", s3base.S3Importer)
    set_handler("map", s3base.S3Map)
    set_handler("mform", s3base.S3MobileCRUD, representation="json")
    set_handler("organize", s3base.S3Organizer)
    set_handler("profile", s3base.S3Profile)
    set_handler("report", s3base.S3Report) # For HTML, JSON
    set_handler("report", s3base.S3Report, transform=True) # For GeoJSON
    set_handler("search_ac", s3base.search_ac)
    set_handler("summary", s3base.S3Summary)
    set_handler("timeplot", s3base.S3TimePlot)
    set_handler("xform", s3base.S3XForms)

    # Don't load S3PDF unless needed (very slow import with Reportlab)
    method = r.method
    if method == "import" and r.representation == "pdf":
        from s3.s3pdf import S3PDF
        set_handler("import", S3PDF(),
                    http = ("GET", "POST"),
                    representation="pdf")

    # Plugin OrgRoleManager when appropriate
    s3base.S3OrgRoleManager.set_method(r)

    # Execute the request
    output = r(**attr)

    if isinstance(output, dict) and \
       method in (None,
                  "report",
                  "search",
                  "datatable",
                  "datatable_f",
                  "summary"):

        if s3.actions is None:

            # Add default action buttons
            prefix, name, table, tablename = r.target()
            authorised = s3_has_permission("update", tablename)

            # If a component has components itself, then action buttons
            # can be forwarded to the native controller by setting native=True
            if r.component and s3db.has_components(table):
                native = output.get("native", False)
            else:
                native = False

            # Get table config
            get_config = s3db.get_config
            listadd = get_config(tablename, "listadd", True)
            editable = get_config(tablename, "editable", True)
            if s3.crud.auto_open_update:
                # "Open" action button without explicit method
                editable = editable and "auto"
            else:
                # "Open" action button with explicit read|update method
                editable = editable and \
                           not auth.permission.ownership_required("update", table)
            deletable = get_config(tablename, "deletable", True)
            copyable = get_config(tablename, "copyable", False)

            # URL to open the resource
            open_url = r.resource.crud._linkto(r,
                                               authorised=authorised,
                                               update=editable,
                                               native=native)("[id]")

            # Add action buttons for Open/Delete/Copy as appropriate
            s3_action_buttons(r,
                              deletable=deletable,
                              copyable=copyable,
                              editable=editable,
                              read_url=open_url,
                              update_url=open_url
                              # To use modals
                              #update_url="%s.popup?refresh=list" % open_url
                              )

            # Override Add-button, link to native controller and put
            # the primary key into get_vars for automatic linking
            if native and not listadd and \
               s3_has_permission("create", tablename):
                label = s3base.S3CRUD.crud_string(tablename,
                                                  "label_create")
                component = r.resource.components[name]
                fkey = "%s.%s" % (name, component.fkey)
                get_vars_copy = get_vars.copy()
                get_vars_copy.update({fkey: r.record[component.fkey]})
                url = URL(prefix, name, args=["create"], vars=get_vars_copy)
                add_btn = A(label, _href=url, _class="action-btn")
                output.update(add_btn=add_btn)

    elif method not in ("import",
                        "review",
                        "approve",
                        "reject",
                        "deduplicate"):
        s3.actions = None

    if get_vars.tour:
        output = s3db.tour_builder(output)

    return output