def parser():

    if not auth.s3_has_role(ADMIN):
        session.error = ERROR.UNAUTHORISED
        redirect(URL(f="index"))

    def prep(r):
        if r.interactive:
            # CRUD Strings
            s3.crud_strings["msg_parser"] = Storage(
                title_display = T("Parser Connection Details"),
                title_list = T("Parser Connections"),
                label_create = T("Connect Parser"),
                title_update = T("Edit Parser Connection"),
                label_list_button = T("View Parser Connections"),
                msg_record_created = T("Parser connected"),
                msg_record_deleted = T("Parser connection removed"),
                msg_record_modified = T("Parser connection updated"),
                msg_list_empty = T("No Parsers currently connected"),
            )

            import inspect
            import sys

            template = settings.get_msg_parser()
            module_name = "applications.%s.modules.templates.%s.parser" % \
                (appname, template)
            __import__(module_name)
            mymodule = sys.modules[module_name]
            S3Parser = mymodule.S3Parser()

            # Dynamic lookup of the parsing functions in S3Parser class.
            parsers = inspect.getmembers(S3Parser, \
                                         predicate=inspect.isfunction)
            parse_opts = []
            pappend = parse_opts.append
            for p in parsers:
                p = p[0]
                # Filter out helper functions
                if not p.startswith("_"):
                    pappend(p)

            table = r.table
            table.channel_id.requires = IS_ONE_OF(db, "msg_channel.channel_id",
                                                  s3base.S3Represent(lookup="msg_channel"),
                                                  sort = True,
                                                  )
            table.function_name.requires = IS_IN_SET(parse_opts,
                                                     zero = None)
        return True
    s3.prep = prep

    def postp(r, output):
        if r.interactive:
            # Normal Action Buttons
            s3_action_buttons(r)
            # Custom Action Buttons for Enable/Disable
            table = r.table
            query = (table.deleted == False)
            rows = db(query).select(table.id,
                                    table.enabled,
                                    )
            restrict_e = [str(row.id) for row in rows if not row.enabled]
            restrict_d = [str(row.id) for row in rows if row.enabled]

            from s3 import s3_str
            s3.actions += [dict(label=s3_str(T("Enable")),
                                _class="action-btn",
                                url=URL(args=["[id]", "enable"]),
                                restrict = restrict_e),
                           dict(label=s3_str(T("Disable")),
                                _class="action-btn",
                                url = URL(args = ["[id]", "disable"]),
                                restrict = restrict_d),
                           ]
            if not s3task._is_alive():
                # No Scheduler Running
                s3.actions += [dict(label=s3_str(T("Parse")),
                                    _class="action-btn",
                                    url = URL(args = ["[id]", "parse"]),
                                    restrict = restrict_d)
                               ]

        return output
    s3.postp = postp

    return s3_rest_controller()

# =============================================================================
# The following functions hook into the pr functions:
#
RESTful CRUD controller for Parsers
dataset/ETHPy150Open sahana/eden/controllers/msg.py/parser