def app_ctx(cfg): namespace_mapping, backend_mapping, acl_mapping = create_simple_mapping( "stores:memory:", cfg.default_acl ) more_config = dict( namespace_mapping=namespace_mapping, backend_mapping=backend_mapping, acl_mapping=acl_mapping, create_storage=True, # create a fresh storage at each app start destroy_storage=True, # kill all storage contents at app shutdown create_index=True, # create a fresh index at each app start destroy_index=True, # kill index contents at app shutdown ) app = create_app_ext( flask_config_dict=dict(SECRET_KEY='foobarfoobar'), moin_config_class=cfg, **more_config ) ctx = app.test_request_context('/', base_url="http://localhost:8080/") ctx.push() before_wiki() yield app, ctx teardown_wiki('') ctx.pop() destroy_app(app)
def run(self, query): before_wiki() if query: qp = app.storage.query_parser([ NAME_EXACT, ]) q = qp.parse(query_text) else: q = Every() for current_rev in app.storage.search(q, limit=None): current_name = current_rev.meta[NAME] current_revid = current_rev.meta[REVID] print "Destroying historical revisions of {0!r}:".format( current_name) has_historical_revision = False for rev in current_rev.item.iter_revs(): revid = rev.meta[REVID] if revid == current_revid: continue has_historical_revision = True name = rev.meta[NAME] if name == current_name: print " Destroying revision {0}".format(revid) else: print " Destroying revision {0} (named {1!r})".format( revid, name) current_rev.item.destroy_revision(revid) if not has_historical_revision: print " (no historical revisions)" print "Finished reducing backend."
def test_url_for_item(self): before_wiki() revid = 'cdc431e0fc624d6fb8372152dcb66457' tests = [(('SomePage', '', '', '', CURRENT, 'frontend.show_item', False), '/SomePage'), # Method signature to understand the tuple parameters # (item_name, wiki_name='', namespace='', rev=CURRENT, endpoint='frontend.show_item', _external=False): (('SomePage', '', '', '', CURRENT, 'frontend.show_item', True), 'http://*****:*****@itemid/SomeItemID'), (('SomePage', 'non-existent', '', 'ns1', CURRENT, 'frontend.show_item', False), '/non-existent/ns1/SomePage'), ] for (item_name, wiki_name, field, namespace, rev, endpoint, _external), url in tests: assert url_for_item(item_name, wiki_name, field, namespace, rev, endpoint, _external) == url
def run(self, name, uid): flags_given = name or uid if not flags_given: print 'incorrect number of arguments' import sys sys.exit() before_wiki() if uid: u = user.User(uid) elif name: u = user.User(auth_username=name) if not u.exists(): print 'This user "{0!r}" does not exists!'.format(u.name) return print " {0:<20} {1!r:<25} {2:<35}".format(u.itemid, u.name, u.email), if not u.disabled: # only disable once u.disabled = 1 u.name = u"{0}-{1}".format(u.name, u.id) if u.email: u.email = u"{0}-{1}".format(u.email, u.id) u.subscriptions = [] u.save() print "- disabled." else: print "- is already disabled."
def run(self, query): before_wiki() if query: qp = app.storage.query_parser([NAME_EXACT, ]) q = qp.parse(query_text) else: q = Every() for current_rev in app.storage.search(q, limit=None): current_name = current_rev.meta[NAME] current_revid = current_rev.meta[REVID] print "Destroying historical revisions of {0!r}:".format(current_name) has_historical_revision = False for rev in current_rev.item.iter_revs(): revid = rev.meta[REVID] if revid == current_revid: continue has_historical_revision = True name = rev.meta[NAME] if name == current_name: print " Destroying revision {0}".format(revid) else: print " Destroying revision {0} (named {1!r})".format(revid, name) current_rev.item.destroy_revision(revid) if not has_historical_revision: print " (no historical revisions)" print "Finished reducing backend."
def run(self, name, display_name, email, openid, password): before_wiki() msg = user.create_user(username=name, password=password, email=email, openid=openid) if msg: print msg else: u = user.User(auth_username=name) print " %-20s %-25s %-35s - created." % (u.itemid, u.name, u.email),
def run(self, name, uid, password, all_users, notify, verbose, subject, text, text_file, skip_invalid): flags_given = name or uid or all_users if not flags_given: print 'incorrect number of arguments' sys.exit(1) if notify and not app.cfg.mail_enabled: print "This wiki is not enabled for mail processing. The --notify option requires this. Aborting..." sys.exit(1) if text_file: with open(text_file) as f: text = f.read().decode('utf-8') before_wiki() if uid: query = {ITEMID: uid} elif name: query = {NAME_EXACT: name} elif all_users: query = {} # sorting the list so we have some specific, reproducable order uids_metas = sorted([(rev.meta[ITEMID], rev.meta) for rev in user.search_users(**query)]) total = len(uids_metas) for nr, (uid, meta) in enumerate(uids_metas, start=1): name = meta[NAME] email = meta.get(EMAIL) if email is None: email = meta.get(EMAIL_UNVALIDATED) if email is None: raise ValueError( "neither EMAIL nor EMAIL_UNVALIDATED key is present in user profile metadata of uid %r name %r" % (uid, name)) else: email += '[email_unvalidated]' try: set_password(uid, password, notify=notify, skip_invalid=skip_invalid, subject=subject, text=text) except Fault as err: status = "FAILURE: [%s]" % str(err) else: status = "SUCCESS" if verbose: print "uid %s, name %s, email %s (%05d / %05d) %s" % ( uid, name, email, nr, total, status)
def init_test_app(given_config): namespace_mapping, router_index_uri = create_simple_mapping( "memory:", given_config.content_acl) more_config = dict( namespace_mapping=namespace_mapping, router_index_uri=router_index_uri, ) app = create_app_ext(flask_config_dict=dict(SECRET_KEY='foobarfoobar'), moin_config_class=given_config, **more_config) ctx = app.test_request_context('/') ctx.push() before_wiki() return app, ctx
def run(self, query): before_wiki() if query: q = And([ Term(WIKINAME, app.cfg.interwikiname), Regex(NAME_EXACT, query) ]) else: q = Every() for current_rev in app.storage.search(q, limit=None): current_name = current_rev.meta[NAME] current_revid = current_rev.meta[REVID] print "Destroying historical revisions of {0!r}:".format( current_name) has_historical_revision = False for rev in current_rev.item.iter_revs(): revid = rev.meta[REVID] if revid == current_revid: # fixup metadata and overwrite existing revision; modified time will be updated if changed changed = False meta = dict(rev.meta) if REV_NUMBER in meta and meta[ REV_NUMBER] > 1 or REV_NUMBER not in meta: changed = True meta[REV_NUMBER] = 1 if PARENTID in meta: changed = True del meta[PARENTID] if changed: current_rev.item.store_revision(meta, current_rev.data, overwrite=True) print " (current rev meta data updated)" continue has_historical_revision = True name = rev.meta[NAME] if name == current_name: print " Destroying revision {0}".format(revid) else: print " Destroying revision {0} (named {1!r})".format( revid, name) current_rev.item.destroy_revision(revid) if not has_historical_revision: print " (no historical revisions)" print "Finished reducing backend."
def init_test_app(given_config): namespace_mapping, acl_mapping = create_simple_mapping("stores:memory:", given_config.content_acl) more_config = dict( namespace_mapping=namespace_mapping, acl_mapping=acl_mapping, create_storage=True, # create a fresh storage at each app start destroy_storage=True, # kill all storage contents at app shutdown create_index=True, # create a fresh index at each app start destroy_index=True, # kill index contents at app shutdown ) app = create_app_ext(flask_config_dict=dict(SECRET_KEY='foobarfoobar'), moin_config_class=given_config, **more_config) ctx = app.test_request_context('/', base_url="http://localhost:8080/") ctx.push() before_wiki() return app, ctx
def run(self, name, uid, password, all_users, notify, verbose, subject, text, text_file, skip_invalid): flags_given = name or uid or all_users if not flags_given: print 'incorrect number of arguments' sys.exit(1) if notify and not app.cfg.mail_enabled: print "This wiki is not enabled for mail processing. The --notify option requires this. Aborting..." sys.exit(1) if text_file: with open(text_file) as f: text = f.read().decode('utf-8') before_wiki() if uid: query = {ITEMID: uid} elif name: query = {NAME_EXACT: name} elif all_users: query = {} # sorting the list so we have some specific, reproducable order uids_metas = sorted([(rev.meta[ITEMID], rev.meta) for rev in user.search_users(**query)]) total = len(uids_metas) for nr, (uid, meta) in enumerate(uids_metas, start=1): name = meta[NAME] email = meta.get(EMAIL) if email is None: email = meta.get(EMAIL_UNVALIDATED) if email is None: raise ValueError("neither EMAIL nor EMAIL_UNVALIDATED key is present in user profile metadata of uid %r name %r" % (uid, name)) else: email += '[email_unvalidated]' try: set_password(uid, password, notify=notify, skip_invalid=skip_invalid, subject=subject, text=text) except Fault as err: status = "FAILURE: [%s]" % str(err) else: status = "SUCCESS" if verbose: print "uid %s, name %s, email %s (%05d / %05d) %s" % (uid, name, email, nr, total, status)
def app_ctx(cfg): namespace_mapping, backend_mapping, acl_mapping = create_simple_mapping( "stores:memory:", cfg.default_acl) more_config = dict( namespace_mapping=namespace_mapping, backend_mapping=backend_mapping, acl_mapping=acl_mapping, create_storage=True, # create a fresh storage at each app start destroy_storage=True, # kill all storage contents at app shutdown create_index=True, # create a fresh index at each app start destroy_index=True, # kill index contents at app shutdown ) app = create_app_ext(flask_config_dict=dict(SECRET_KEY='foobarfoobar'), moin_config_class=cfg, **more_config) ctx = app.test_request_context('/', base_url="http://localhost:8080/") ctx.push() before_wiki() yield app, ctx teardown_wiki('') ctx.pop() destroy_app(app)
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, 'MoinMoin')) # 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 u'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 = Config.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 = u' 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 u'Failed to dump {0}: Forbidden'.format(current_rev.name) continue except KeyError: print u'Failed to dump {0}: KeyError'.format(current_rev.name) continue if not isinstance(rendered, unicode): print u'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="">', u'<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.name] 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 u'Saved file named {0} as raw data'.format( filename).encode('utf-8') else: with open(filename, 'wb') as f: f.write(rendered.encode('utf8')) print u'Saved file named {0}'.format(filename).encode( 'utf-8') 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 = u'<h1>Index</h1><ul>{0}</ul>' li = u'<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(u'\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 u'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'
def make_context(): before_wiki() return dict(app=app, flaskg=flaskg)