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
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
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' )
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, ), ) """
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
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
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, ), ) """