Example #1
0
    def add_module(self, module_name):
        """
        Register a new XStatic module.

        For example, if you want to use jquery, call xs.add_module('jquery').
        Note that in that case, you need to have "xstatic-jquery" installed.
        """
        pkg = __import__('xstatic.pkg', fromlist=[module_name])
        module = getattr(pkg, module_name)
        xs = XStatic(
            module,
            root_url='/xstatic',
            provider='local',
            protocol='http',
        )
        self.serve_files[xs.name] = xs.base_dir
Example #2
0
def _xstatic(name):
    mod_names = [
        'jquery', 'bootstrap',
    ]
    pkg = __import__('xstatic.pkg', fromlist=mod_names)
    serve_files = {}

    for mod_name in mod_names:
        mod = getattr(pkg, mod_name)
        # ToDo protocol should become configurable
        xs = XStatic(mod, root_url='/static', provider='local', protocol='http')
        serve_files[xs.name] = xs.base_dir
    try:
        return serve_files[name]
    except KeyError:
        return None
Example #3
0
    def run(self,
            directory='HTML',
            theme='topside_cms',
            exclude_ns='userprofiles',
            user=None,
            query=None):
        if theme:
            app.cfg.user_defaults[THEME_NAME] = theme
        exclude_ns = exclude_ns.split(',') if exclude_ns else []

        before_wiki()

        norm = os.path.normpath
        join = os.path.join

        if '/' in directory:
            # user has specified complete path to root
            html_root = directory
        else:
            html_root = norm(join(app.cfg.wikiconfig_dir, directory))
        repo_root = norm(join(app.cfg.wikiconfig_dir))
        moinmoin = norm(join(app.cfg.wikiconfig_dir, 'src', 'moin'))

        # override ACLs with permission to read all items
        for namespace, acls in app.cfg.acl_mapping:
            acls['before'] = 'All:read'

        # create an empty output directory after deleting any existing directory
        print(
            'Creating output directory {0}, starting to copy supporting files'.
            format(html_root))
        if os.path.exists(html_root):
            shutil.rmtree(html_root, ignore_errors=False)
        else:
            os.makedirs(html_root)

        # create subdirectories and copy static css, icons, images into "static" subdirectory
        shutil.copytree(norm(join(moinmoin, 'static')),
                        norm(join(html_root, 'static')))
        shutil.copytree(norm(join(repo_root, 'wiki_local')),
                        norm(join(html_root, '+serve/wiki_local')))

        # copy files from xstatic packaging into "+serve" subdirectory
        pkg = app.cfg.pkg
        xstatic_dirs = [
            'font_awesome', 'jquery', 'jquery_tablesorter', 'autosize'
        ]
        if theme in [
                'basic',
        ]:
            xstatic_dirs.append('bootstrap')
        for dirs in xstatic_dirs:
            xs = XStatic(getattr(pkg, dirs),
                         root_url='/static',
                         provider='local',
                         protocol='http')
            shutil.copytree(xs.base_dir, norm(join(html_root, '+serve', dirs)))

        # copy directories for theme's static files
        theme = app.cfg.user_defaults[THEME_NAME]
        if theme == 'topside_cms':
            # topside_cms uses topside CSS files
            from_dir = norm(join(moinmoin, 'themes/topside/static'))
        else:
            from_dir = norm(join(moinmoin, 'themes', theme, 'static'))
        to_dir = norm(join(html_root, '_themes', theme))
        shutil.copytree(from_dir, to_dir)

        # convert: <img alt="svg" src="/+get/+7cb364b8ca5d4b7e960a4927c99a2912/svg" />
        # to:      <img alt="svg" src="+get/svg" />
        invalid_src = re.compile(r' src="/\+get/\+[0-9a-f]{32}/')
        valid_src = ' src="+get/'

        # get ready to render and copy individual items
        names = []
        home_page = None
        get_dir = norm(join(
            html_root, '+get'))  # images and other raw data from wiki content
        os.makedirs(get_dir)

        if query:
            q = And([
                Term(WIKINAME, app.cfg.interwikiname),
                Regex(NAME_EXACT, query)
            ])
        else:
            q = Every()

        print('Starting to dump items')
        for current_rev in app.storage.search(q, limit=None, sortedby="name"):
            if current_rev.namespace in exclude_ns:
                # we usually do not copy userprofiles, no one can login to a static wiki
                continue
            if not current_rev.name:
                # TODO: we skip nameless tickets, but named tickets and comments are processed with ugly names
                continue

            try:
                item_name = current_rev.fqname.fullname
                rendered = show_item(
                    item_name, CURRENT)  # @@@  userid is needed for acls here
                # convert / characters in sub-items and namespaces and save names for index
                file_name = item_name.replace('/', SLASH)
                filename = norm(join(html_root, file_name))
                names.append(file_name)
            except Forbidden:
                print('Failed to dump {0}: Forbidden'.format(current_rev.name))
                continue
            except KeyError:
                print('Failed to dump {0}: KeyError'.format(current_rev.name))
                continue

            if not isinstance(rendered, str):
                print('Rendering failed for {0} with response {1}'.format(
                    file_name, rendered))
                continue
            # make hrefs relative to current folder
            rendered = rendered.replace('href="/', 'href="')
            rendered = rendered.replace('src="/static/', 'src="static/')
            rendered = rendered.replace('src="/+serve/', 'src="+serve/')
            rendered = rendered.replace(
                'href="+index/"',
                'href="+index"')  # trailing slash changes relative position
            rendered = rendered.replace('<a href="">', '<a href="{0}">'.format(
                app.cfg.default_root))  # TODO: fix basic theme
            # remove item ID from: src="/+get/+7cb364b8ca5d4b7e960a4927c99a2912/svg"
            rendered = re.sub(invalid_src, valid_src, rendered)
            rendered = self.subitems(rendered)

            # copy raw data for all items to output /+get directory; images are required, text items are of marginal/no benefit
            item = app.storage[current_rev.fqname.fullname]
            rev = item[CURRENT]
            with open(get_dir + '/' + file_name, 'wb') as f:
                shutil.copyfileobj(rev.data, f)

            # save rendered items or raw data to dump directory root
            contenttype = item.meta['contenttype'].split(';')[0]
            if contenttype in CONTENTTYPE_MEDIA and filename.endswith(
                    CONTENTTYPE_MEDIA_SUFFIX):
                # do not put a rendered html-formatted file with a name like video.mp4 into root; browsers want raw data
                with open(filename, 'wb') as f:
                    rev.data.seek(0)
                    shutil.copyfileobj(rev.data, f)
                    print('Saved file named {0} as raw data'.format(filename))
            else:
                with open(filename, 'wb') as f:
                    f.write(rendered.encode('utf8'))
                    print('Saved file named {0}'.format(filename))

            if current_rev.name == app.cfg.default_root:
                # make duplicates of home page that are easy to find in directory list and open with a click
                for target in [(current_rev.name + '.html'),
                               ('_' + current_rev.name + '.html')]:
                    with open(norm(join(html_root, target)), 'wb') as f:
                        f.write(rendered.encode('utf8'))
                home_page = rendered  # save a copy for creation of index page

        if home_page:
            # create an index page by replacing the content of the home page with a list of items
            # work around differences in basic and modernized theme layout
            # TODO: this is likely to break as new themes are added
            if theme == 'basic':
                start = '<div class="moin-content" role="main">'  # basic
                end = '<footer class="navbar moin-footer">'
                div_end = '</div>'
            else:
                start = '<div id="moin-content">'  # modernized , topside, topside cms
                end = '<footer id="moin-footer">'
                div_end = '</div></div>'
            # build a page named "+index" containing links to all wiki items
            ul = '<h1>Index</h1><ul>{0}</ul>'
            li = '<li><a href="{0}">{1}</a></li>'
            links = []
            names.sort()
            for name in names:
                links.append(li.format(name, name.replace(SLASH, '/')))
            name_links = ul.format('\n'.join(links))
            try:
                part1 = home_page.split(start)[0]
                part2 = home_page.split(end)[1]
                page = part1 + start + name_links + div_end + end + part2
            except IndexError:
                page = home_page
                print('Error: failed to find {0} in item named {1}'.format(
                    end, app.cfg.default_root))
            for target in ['+index', '_+index.html']:
                with open(norm(join(html_root, target)), 'wb') as f:
                    f.write(page.encode('utf8'))
        else:
            print(
                'Error: no item matching name in app.cfg.default_root was found'
            )
Example #4
0
class Config(DefaultConfig):

    # We assume this structure for a git clone or simple "unpack and run" scenario:
    # moin-2.0/                     # wikiconfig_dir points here: clone root or unpack directory, contains this file.
    #     wikiconfig.py             # the file you are reading now.
    #     wiki/                     # instance_dir variable points here: created by running "./m sample" or "./m new-wiki" commands.
    #         data/                 # data_dir variable points here.
    #         index/                # index_storage variable points here.
    #     contrib/
    #         interwiki/
    #             intermap.txt      # interwiki_map variable points here.
    #     docs/
    #         _build/
    #             html/             # serve_files['docs']: html docs made by sphinx, create by running "./m docs" command.
    #     wiki_local/               # serve_files['wiki_local']: store custom logos, CSS, templates, etc. here
    # If that's not true, adjust these paths
    wikiconfig_dir = os.path.abspath(os.path.dirname(__file__))
    instance_dir = os.path.join(wikiconfig_dir, 'wiki')
    data_dir = os.path.join(instance_dir, 'data')
    index_storage = 'FileStorage', (os.path.join(instance_dir, "index"), ), {}
    # setup static files' serving:
    serve_files = dict(
        docs=os.path.join(wikiconfig_dir, 'docs', '_build',
                          'html'),  # html docs made by sphinx
        wiki_local=os.path.join(
            wikiconfig_dir,
            'wiki_local'),  # store custom logos, CSS, templates, etc. here
    )
    # copy templates/snippets.html to directory below and edit per requirements to customize logos, etc.
    template_dirs = [
        os.path.join(wikiconfig_dir, 'wiki_local'),
    ]

    # it is required that you set this to a unique, stable and non-empty name:
    interwikiname = u'MyMoinMoin'
    # load the interwiki map from intermap.txt:
    interwiki_map = InterWikiMap.from_file(
        os.path.join(wikiconfig_dir, 'contrib', 'interwiki',
                     'intermap.txt')).iwmap
    # we must add entries for 'Self' and our interwikiname, change these if you are not running the built-in desktop server:
    interwiki_map[interwikiname] = 'http://127.0.0.1:8080/'
    interwiki_map['Self'] = 'http://127.0.0.1:8080/'

    # sitename is displayed in heading of all wiki pages
    sitename = u'My MoinMoin'

    # default theme is topside
    # theme_default = u"modernized"  # or basic or topside_cms

    # read about PRIVACY ISSUES in docs before uncommenting the line below to use gravatars
    # user_use_gravatar = True

    # read about SECURITY ISSUES in docs before uncommenting the line below allowing users
    # to edit style attributes in HTML and Markdown items
    # allow_style_attributes = True

    # default passwords are required to be => 8 characters with minimum of 5 unique characters
    # password_checker = None  # no password length or quality checking
    # password_checker = lambda cfg, name, pw: _default_password_checker(cfg, name, pw, min_length=8, min_different=5)  # default

    # optional, configure email, uncomment line below and choose (a) or (b)
    # mail_from = u"wiki <*****@*****.**>"  # the "from:" address [Unicode]
    # (a) using an SMTP server, e.g. "mail.provider.com" with optional `:port`appendix, which defaults to 25 (set None to disable mail)
    # mail_smarthost = "smtp.example.org"
    # mail_username = "******"  # if you need to use SMTP AUTH at your mail_smarthost:
    # mail_password = "******"
    # (b) an alternative to SMTP is the sendmail commandline tool:
    # mail_sendmail = "/usr/sbin/sendmail -t -i"

    # list of admin emails
    admin_emails = []
    # send tracebacks to admins
    email_tracebacks = False

    # add or remove packages - see https://bitbucket.org/thomaswaldmann/xstatic for info about xstatic
    # it is uncommon to change these because of local customizations
    from xstatic.main import XStatic
    # names below must be package names
    mod_names = [
        'jquery',
        'jquery_file_upload',
        'bootstrap',
        'font_awesome',
        'ckeditor',
        'autosize',
        'svgedit_moin',
        'twikidraw_moin',
        'anywikidraw',
        'jquery_tablesorter',
        'pygments',
    ]
    pkg = __import__('xstatic.pkg', fromlist=mod_names)
    for mod_name in mod_names:
        mod = getattr(pkg, mod_name)
        xs = XStatic(mod,
                     root_url='/static',
                     provider='local',
                     protocol='http')
        serve_files[xs.name] = xs.base_dir

    # create a super user who will have access to administrative functions
    # acl_functions = u'+YourName:superuser'
    # OR, create several WikiGroups and create several superusers
    # SuperGroup and TrustedEditorGroup reference WikiGroups you must create
    # acl_functions = u'+YourName:superuser SuperGroup:superuser'

    # This provides a simple default setup for your backend configuration.
    # 'stores:fs:...' indicates that you want to use the filesystem backend.
    # Alternatively you can set up the mapping yourself (see HelpOnStorageConfiguration).
    namespace_mapping, backend_mapping, acl_mapping = create_simple_mapping(
        uri='stores:fs:{0}/%(backend)s/%(kind)s'.format(data_dir),
        # XXX we use rather relaxed ACLs for the development wiki:
        default_acl=dict(
            before=u'',
            default=u'All:read,write,create,destroy,admin',
            after=u'',
            hierarchic=False,
        ),
        users_acl=dict(
            before=u'',
            default=u'All:read,write,create,destroy,admin',
            after=u'',
            hierarchic=False,
        ),
        # userprofiles contain only metadata, no content will be created
        userprofiles_acl=dict(
            before=u'All:',
            default=u'',
            after=u'',
            hierarchic=False,
        ),
    )
    """
Example #5
0
from xstatic.main import XStatic

# names below must be package names
mod_names = [
    'asciinema_player',
    'bootbox',
    'bootstrap',
    'jquery',
    'jquery_ui',
    'jquery_file_upload',
    'pygments',
]

pkg = __import__('xstatic.pkg', fromlist=mod_names)
serve_files = {}
for mod_name in mod_names:
    mod = getattr(pkg, mod_name)
    xs = XStatic(mod, root_url='/static', provider='local', protocol='http')
    serve_files[xs.name] = xs.base_dir
Example #6
0
class Config(DefaultConfig):
    # Directory containing THIS wikiconfig:
    wikiconfig_dir = os.path.abspath(os.path.dirname(__file__))
    # We assume this structure for a simple "unpack and run" scenario:
    # wikiconfig.py
    # wiki/
    #      data/
    #      index/
    # contrib/
    #      interwiki/
    #          intermap.txt
    # If that's not true, feel free to adjust the pathes.
    instance_dir = os.path.join(wikiconfig_dir, 'wiki')
    data_dir = os.path.join(
        instance_dir,
        'data')  # Note: this used to have a trailing / in the past
    index_storage = 'FileStorage', (os.path.join(instance_dir, "index"), ), {}

    # This provides a simple default setup for your backend configuration.
    # 'stores:fs:...' indicates that you want to use the filesystem backend.
    # Alternatively you can set up the mapping yourself (see HelpOnStorageConfiguration).
    namespace_mapping, backend_mapping, acl_mapping = create_simple_mapping(
        uri='stores:fs:{0}/%(backend)s/%(kind)s'.format(data_dir),
        # XXX we use rather relaxed ACLs for the development wiki:
        default_acl=dict(
            before=u'',
            default=u'All:read,write,create,destroy,admin',
            after=u'',
            hierarchic=False,
        ),
        userprofiles_acl=dict(
            before=u'',
            default=u'All:read,write,create,destroy,admin',
            after=u'',
            hierarchic=False,
        ),
    )

    # for display purposes:
    sitename = u'My MoinMoin'
    # it is required that you set this to a unique, stable and non-empty name:
    interwikiname = u'MyMoinMoin'
    # Load the interwiki map from intermap.txt:
    interwiki_map = InterWikiMap.from_file(
        os.path.join(wikiconfig_dir, 'contrib', 'interwiki',
                     'intermap.txt')).iwmap
    # we must add entries for 'Self' and our interwikiname:
    interwiki_map[interwikiname] = 'http://127.0.0.1:8080/'
    interwiki_map['Self'] = 'http://127.0.0.1:8080/'

    # setup static files' serving:
    serve_files = dict(
        docs=os.path.join(wikiconfig_dir, 'docs', '_build',
                          'html'),  # html docs made by sphinx
    )
    # see https://bitbucket.org/thomaswaldmann/xstatic for infos about xstatic:
    from xstatic.main import XStatic
    # names below must be package names
    mod_names = [
        'jquery',
        'jquery_file_upload',
        'bootstrap',
        'font_awesome',
        'ckeditor',
        'autosize',
        'svgedit_moin',
        'twikidraw_moin',
        'anywikidraw',
        'jquery_tablesorter',
        'pygments',
    ]
    pkg = __import__('xstatic.pkg', fromlist=mod_names)
    for mod_name in mod_names:
        mod = getattr(pkg, mod_name)
        xs = XStatic(mod,
                     root_url='/static',
                     provider='local',
                     protocol='http')
        serve_files[xs.name] = xs.base_dir

    # list of admin emails
    admin_emails = []
    # send tracebacks to admins
    email_tracebacks = False
Example #7
0
class Config(DefaultConfig):
    """
    We assume this structure for a git clone scenario used by developers:

        moin/                   # clone root and wikiconfig dir, use this as CWD for ./m or moin commands
            contrib             # developer tools
            docs/
                _build/
                    html/       # local copy of moin documentation, created by running "./m docs" command
            src/
                moin/           # directory containing moin application code
            wiki/               # the wiki instance; created by running "./m sample" or "./m new-wiki" commands
                data/           # wiki data and metadata
                index/          # wiki indexes
                preview/        # edit backups created when user clicks edit Preview button
                sql/            # sql database used for edit locking
            wikiconfig.py       # main configuration file, modify this to add or change features
            wiki_local/         # use this to store custom CSS, Javascript, templates, logos, etc.
            intermap.txt        # list of external wikis used in wikilinks: [[MeatBall:InterWiki]]
        <moin-venv-python>      # virtual env is created as a sibling to moin/ by default
            bin/                # Windows calls this directory Scripts
            include             # Windows calls this directory Include
            lib/                # Windows calls this directory Lib


    OR: To install moin from pypi into a venv, enter this sequence of commands:
        <python> -m venv <myvenv>
        cd <path-to-new-myvenv>
        source bin/activate activate  # Scripts\activate.bat
        pip install wheel
        pip install moin
        moin create-instance --path <mywiki>
        cd <mywiki>
        moin index-create -s -i                                 # creates empty wiki, OR
        moin import19 -s -i --data_dir <path to 1.9 wiki/data>  # import 1.9 data, OR
        moin index-create; moin load-sample; moin index-build   # creates wiki with sample data
    to create this structure:

        <myvenv>/               # virtualenv root, moin installed in site-packages below include/
            bin/                # Windows calls this directory Scripts
            include/            # Windows calls this directory Include
            lib/                # Windows calls this directory Lib
        <mywiki>/               # wikiconfig dir, use this as CWD for moin commands after <myvenv> activated
            wiki/               # the wiki instance; created by `moin create-instance`
                data/           # wiki data and metadata
                index/          # wiki indexes
                preview/        # backups created when user clicks edit Preview button
                sql/            # sqlite database used for edit locking
            wiki-local/         # store custom CSS, Javascript, templates, logos, etc. here
            wikiconfig.py       # main configuration file, modify this to add or change features
            intermap.txt        # list of external wikis used in wikilinks: [[MeatBall:InterWiki]]

    If that's not true, adjust these paths
    """
    wikiconfig_dir = os.path.abspath(os.path.dirname(__file__))
    instance_dir = os.path.join(wikiconfig_dir, 'wiki')
    data_dir = os.path.join(instance_dir, 'data')
    index_storage = 'FileStorage', (os.path.join(instance_dir, "index"), ), {}

    # setup static files' serving:
    serve_files = dict(
        wiki_local=os.path.join(
            wikiconfig_dir,
            'wiki_local'),  # store custom logos, CSS, templates, etc. here
    )
    docs = os.path.join(wikiconfig_dir, 'docs', '_build', 'html')
    if os.path.isdir(docs):
        serve_files['docs'] = docs
    else:
        # change target if a specific release or language is available
        serve_files[
            'external_docs'] = "https://moin-20.readthedocs.io/en/latest/"

    # copy templates/snippets.html to directory below and edit per requirements to customize logos, etc.
    template_dirs = [
        os.path.join(wikiconfig_dir, 'wiki_local'),
    ]

    # it is required that you set interwikiname to a unique, stable and non-empty name.
    # Changing interwikiname on an existing wiki requires rebuilding the index.
    interwikiname = 'MyMoinMoin'
    # load the interwiki map from intermap.txt
    try:
        interwiki_map = InterWikiMap.from_file(
            os.path.join(wikiconfig_dir, 'intermap.txt')).iwmap
    except FileNotFoundError:
        interwiki_map = {}
    # we must add entries for 'Self' and our interwikiname,
    # if you are not running the built-in desktop server change these to your wiki URL
    interwiki_map[interwikiname] = 'http://127.0.0.1:8080/'
    interwiki_map['Self'] = 'http://127.0.0.1:8080/'

    # sitename is displayed in heading of all wiki pages
    sitename = 'My MoinMoin'

    # default theme is topside
    # theme_default = "modernized"  # or basic or topside_cms

    # read about PRIVACY ISSUES in docs before uncommenting the line below to use gravatars
    # user_use_gravatar = True

    # read about SECURITY ISSUES in docs before uncommenting the line below allowing users
    # to edit style attributes in HTML and Markdown items
    # allow_style_attributes = True

    # default passwords are required to be => 8 characters with minimum of 5 unique characters
    # password_checker = None  # no password length or quality checking
    # password_checker = lambda cfg, name, pw: _default_password_checker(cfg, name, pw, min_length=8, min_different=5)  # default

    # optional, configure email, uncomment line below and choose (a) or (b)
    # mail_from = "wiki <*****@*****.**>"  # the "from:" address [Unicode]
    # (a) using an SMTP server, e.g. "mail.provider.com" with optional `:port`appendix, which defaults to 25 (set None to disable mail)
    # mail_smarthost = "smtp.example.org"
    # mail_username = "******"  # if you need to use SMTP AUTH at your mail_smarthost:
    # mail_password = "******"
    # (b) an alternative to SMTP is the sendmail commandline tool:
    # mail_sendmail = "/usr/sbin/sendmail -t -i"

    # list of admin emails
    admin_emails = []
    # send tracebacks to admins
    email_tracebacks = False

    # options for new user registration
    # registration_only_by_superuser = True  # disables self-registration, recommended for public wikis on internet
    # registration_hint = 'To request an account, see bottom of <a href="/Home">Home</a> page.'

    # add or remove packages - see https://bitbucket.org/thomaswaldmann/xstatic for info about xstatic
    # it is uncommon to change these because of local customizations
    from xstatic.main import XStatic
    # names below must be package names
    mod_names = [
        'jquery',
        'jquery_file_upload',
        'bootstrap',
        'font_awesome',
        'ckeditor',
        'autosize',
        'svgedit_moin',
        'twikidraw_moin',
        'anywikidraw',
        'jquery_tablesorter',
        'pygments',
    ]
    pkg = __import__('xstatic.pkg', fromlist=mod_names)
    for mod_name in mod_names:
        mod = getattr(pkg, mod_name)
        xs = XStatic(mod,
                     root_url='/static',
                     provider='local',
                     protocol='http')
        serve_files[xs.name] = xs.base_dir

    # create a super user who will have access to administrative functions
    # acl_functions = '+YourName:superuser'
    # OR, create several WikiGroups and create several superusers
    # SuperGroup and TrustedEditorGroup reference WikiGroups you must create
    # acl_functions = '+YourName:superuser SuperGroup:superuser'

    # This provides a simple default setup for your backend configuration.
    # 'stores:fs:...' indicates that you want to use the filesystem backend.
    # Alternatively you can set up the mapping yourself (see HelpOnStorageConfiguration).
    namespace_mapping, backend_mapping, acl_mapping = create_simple_mapping(
        uri='stores:fs:{0}/%(backend)s/%(kind)s'.format(data_dir),
        # XXX we use rather relaxed ACLs for the development wiki:
        default_acl=dict(
            before='',
            default='All:read,write,create,destroy,admin',
            after='',
            hierarchic=False,
        ),
        users_acl=dict(
            before='',
            default='All:read,write,create,destroy,admin',
            after='',
            hierarchic=False,
        ),
        # userprofiles contain only metadata, no content will be created
        userprofiles_acl=dict(
            before='All:',
            default='',
            after='',
            hierarchic=False,
        ),
        help_common_acl=dict(
            before='',
            default='All:read,write,create,destroy',
            after='',
            hierarchic=False,
        ),
        help_en_acl=dict(
            before='',
            default='All:read,write,create,destroy',
            after='',
            hierarchic=False,
        ),
    )
    """