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
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
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