Mercurial > wikked
changeset 82:9afe4a1dbd1e
Refactoring of core wiki classes:
- Use proper classes instead of dictionaries more often.
- Simplified `Page`'s public API.
- Page meta property values are now always stored in an array, even if there's
only one occurence for the given key.
- Updated unit-tests.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Tue, 19 Mar 2013 19:54:11 -0700 |
parents | 05d0a7cd85e8 |
children | 65f83a9b42f1 |
files | tests/mock.py tests/test_page.py wikked/auth.py wikked/db.py wikked/formatter.py wikked/fs.py wikked/indexer.py wikked/page.py wikked/views.py wikked/wiki.py |
diffstat | 10 files changed, 240 insertions(+), 193 deletions(-) [+] |
line wrap: on
line diff
--- a/tests/mock.py Wed Feb 27 22:55:11 2013 -0800 +++ b/tests/mock.py Tue Mar 19 19:54:11 2013 -0700 @@ -5,7 +5,7 @@ import logging import StringIO from wikked.page import Page -from wikked.fs import PageNotFoundError +from wikked.fs import PageInfo, PageNotFoundError from wikked.db import Database from wikked.indexer import WikiIndex from wikked.scm import SourceControl @@ -132,12 +132,9 @@ def _getPageInfo(self, node, with_content=False): path_split = os.path.splitext(node['path']) url = self.slugify(path_split[0]) - info = { - 'url': url, - 'path': node['path'] - } + info = PageInfo(url, node['path']) if with_content: - info['content'] = node['content'] + info.content = node['content'] return info def _getNode(self, path):
--- a/tests/test_page.py Wed Feb 27 22:55:11 2013 -0800 +++ b/tests/test_page.py Tue Mar 19 19:54:11 2013 -0700 @@ -16,11 +16,11 @@ page = Page(self.wiki, 'foo') self.assertEqual('foo', page.url) self.assertEqual('A test page.', page.raw_text) - self.assertEqual('A test page.', page.formatted_text) + self.assertEqual('A test page.', page._getFormattedText()) self.assertEqual('foo', page.title) self.assertEqual('A test page.', page.text) - self.assertEqual({}, page.local_meta) - self.assertEqual([], page.local_links) + self.assertEqual({}, page._getLocalMeta()) + self.assertEqual([], page._getLocalLinks()) def testPageMeta(self): self.wiki = self._getWikiFromStructure({ @@ -29,11 +29,11 @@ page = Page(self.wiki, 'foo') self.assertEqual('foo', page.url) self.assertEqual("A page with simple meta.\n{{bar: baz}}\n{{is_test: }}", page.raw_text) - self.assertEqual('A page with simple meta.\n\n', page.formatted_text) + self.assertEqual('A page with simple meta.\n\n', page._getFormattedText()) self.assertEqual('foo', page.title) self.assertEqual('A page with simple meta.\n\n', page.text) - self.assertEqual({'bar': 'baz', 'is_test': True}, page.local_meta) - self.assertEqual([], page.local_links) + self.assertEqual({'bar': ['baz'], 'is_test': True}, page._getLocalMeta()) + self.assertEqual([], page._getLocalLinks()) def testPageTitleMeta(self): self.wiki = self._getWikiFromStructure({ @@ -42,11 +42,11 @@ page = Page(self.wiki, 'test_title') self.assertEqual('test_title', page.url) self.assertEqual("A page with a custom title.\n{{title: TEST-TITLE}}", page.raw_text) - self.assertEqual('A page with a custom title.\n', page.formatted_text) + self.assertEqual('A page with a custom title.\n', page._getFormattedText()) self.assertEqual('TEST-TITLE', page.title) self.assertEqual('A page with a custom title.\n', page.text) - self.assertEqual({'title': 'TEST-TITLE'}, page.local_meta) - self.assertEqual([], page.local_links) + self.assertEqual({'title': ['TEST-TITLE']}, page._getLocalMeta()) + self.assertEqual([], page._getLocalLinks()) def testPageOutLinks(self): self.wiki = self._getWikiFromStructure({ @@ -61,8 +61,8 @@ "Follow a link to the %s. Or to %s." % ( format_link('Sandbox', 'sandbox'), format_link('this page', 'other-sandbox', True)), - page.formatted_text) - self.assertEqual(set(['sandbox', 'other-sandbox']), set(page.local_links)) + page.text) + self.assertEqual(set(['sandbox', 'other-sandbox']), set(page._getLocalLinks())) def testPageRelativeOutLinks(self): self.wiki = self._getWikiFromStructure({ @@ -74,20 +74,20 @@ } }) first = Page(self.wiki, 'first') - self.assertEqual(['first-sibling'], first.local_links) + self.assertEqual(['first-sibling'], first._getLocalLinks()) first2 = Page(self.wiki, 'first-sibling') - self.assertEqual(['first', 'sub_dir/second'], first2.local_links) + self.assertEqual(['first', 'sub_dir/second'], first2._getLocalLinks()) second = Page(self.wiki, 'sub_dir/second') - self.assertEqual(['first', 'sub_dir/second-sibling'], second.local_links) + self.assertEqual(['first', 'sub_dir/second-sibling'], second._getLocalLinks()) second2 = Page(self.wiki, 'sub_dir/second-sibling') - self.assertEqual(['sub_dir/second'], second2.local_links) + self.assertEqual(['sub_dir/second'], second2._getLocalLinks()) def testGenericUrl(self): self.wiki = self._getWikiFromStructure({ 'foo.txt': "URL: [[url:/blah/boo/image.png]]" }) foo = Page(self.wiki, 'foo') - self.assertEqual("URL: /files/blah/boo/image.png", foo.formatted_text) + self.assertEqual("URL: /files/blah/boo/image.png", foo._getFormattedText()) def testPageInclude(self): self.wiki = self._getWikiFromStructure({ @@ -95,10 +95,10 @@ 'Trans Desc.txt': "BLAH\n" }) foo = Page(self.wiki, 'foo') - self.assertEqual({'include': 'trans-desc'}, foo.local_meta) + self.assertEqual({'include': ['trans-desc']}, foo._getLocalMeta()) self.assertEqual( "A test page.\n%s" % format_include('trans-desc'), - foo.formatted_text) + foo._getFormattedText()) self.assertEqual("A test page.\nBLAH\n\n", foo.text) def testPageIncludeWithMeta(self): @@ -107,16 +107,16 @@ 'Trans Desc.txt': "BLAH: [[Somewhere]]\n{{bar: 42}}\n{{__secret: love}}\n{{+given: hope}}" }) foo = Page(self.wiki, 'foo') - self.assertEqual([], foo.local_links) - self.assertEqual({'include': 'trans-desc'}, foo.local_meta) + self.assertEqual([], foo._getLocalLinks()) + self.assertEqual({'include': ['trans-desc']}, foo._getLocalMeta()) self.assertEqual( "A test page.\n%s" % format_include('trans-desc'), - foo.formatted_text) + foo._getFormattedText()) self.assertEqual( "A test page.\nBLAH: %s\n\n\n\n" % format_link('Somewhere', 'somewhere', True), foo.text) - self.assertEqual(['somewhere'], foo.all_links) - self.assertEqual({'bar': '42', 'given': 'hope', 'include': 'trans-desc'}, foo.all_meta) + self.assertEqual(['somewhere'], foo.links) + self.assertEqual({'bar': ['42'], 'given': ['hope'], 'include': ['trans-desc']}, foo.meta) def testPageIncludeWithTemplating(self): self.wiki = self._getWikiFromStructure({ @@ -126,7 +126,7 @@ foo = Page(self.wiki, 'foo') self.assertEqual( "A test page.\n%s" % format_include('greeting', 'name=Dave|what=drink'), - foo.formatted_text) + foo._getFormattedText()) self.assertEqual("A test page.\nHello Dave, would you like a drink?\n", foo.text) def testGivenOnlyInclude(self): @@ -138,7 +138,7 @@ tpl1 = Page(self.wiki, 'template-1') self.assertEqual( "TEMPLATE!\n%s" % format_include('template-2', mod='+'), - tpl1.formatted_text) + tpl1._getFormattedText()) self.assertEqual("TEMPLATE!\n\n", tpl1.text) base = Page(self.wiki, 'base') self.assertEqual("The base page.\nTEMPLATE!\nMORE TEMPLATE!\n\n", base.text) @@ -155,16 +155,16 @@ }) base = Page(self.wiki, 'base') self.assertEqual({ - 'foo': 'bar', + 'foo': ['bar'], 'category': ['blah', 'yolo'] - }, base.all_meta) + }, base.meta) tpl1 = Page(self.wiki, 'template-1') self.assertEqual({ - 'foo': 'bar', - '+category': 'blah', - '+include': 'template-2', - '__secret': 'ssh' - }, tpl1.all_meta) + 'foo': ['bar'], + '+category': ['blah'], + '+include': ['template-2'], + '__secret': ['ssh'] + }, tpl1.meta) self.assertEqual( "\n\n%s\n\n" % format_include('template-2'), tpl1.text)
--- a/wikked/auth.py Wed Feb 27 22:55:11 2013 -0800 +++ b/wikked/auth.py Tue Mar 19 19:54:11 2013 -0700 @@ -56,8 +56,8 @@ if (self._permissions[meta_name] is not None and username not in self._permissions[meta_name]): return False - if meta_name in page.all_meta: - allowed = [r.strip() for r in re.split(r'[ ,;]', page.all_meta[meta_name])] + if meta_name in page.meta: + allowed = [r.strip() for r in re.split(r'[ ,;]', page.meta[meta_name][0])] if username is None: return 'anonymous' in allowed else:
--- a/wikked/db.py Wed Feb 27 22:55:11 2013 -0800 +++ b/wikked/db.py Tue Mar 19 19:54:11 2013 -0700 @@ -64,6 +64,19 @@ raise NotImplementedError() + +class SQLitePageInfo(object): + def __init__(self, row): + self.url = row['url'] + self.path = row['path'] + self.time = row['time'] + self.title = row['title'] + self.raw_text = row['raw_text'] + self.formatted_text = row['formatted_text'] + self.links = [] + self.meta = {} + + class SQLiteDatabase(Database): """ A database cache based on SQLite. """ @@ -286,10 +299,10 @@ (time, url, path, title, raw_text, formatted_text) VALUES (?, ?, ?, ?, ?, ?)''', (now, page.url, page.path, page.title, - page.raw_text, page.formatted_text)) + page.raw_text, page._getFormattedText())) page_id = c.lastrowid - for name, value in page.local_meta.iteritems(): + for name, value in page._getLocalMeta().iteritems(): if isinstance(value, bool): value = "" if isinstance(value, types.StringTypes): @@ -302,7 +315,7 @@ (page_id, name, value) VALUES (?, ?, ?)''', (page_id, name, v)) - for link_url in page.local_links: + for link_url in page._getLocalLinks(): c.execute('''INSERT INTO links (source, target) VALUES (?, ?)''', (page.url, link_url)) @@ -317,21 +330,12 @@ c.execute('''DELETE FROM links WHERE source=?''', (row['url'],)) def _getPage(self, row, c): - db_page = { - 'url': row['url'], - 'path': row['path'], - 'time': row['time'], - 'title': row['title'], - 'content': row['raw_text'], - 'formatted': row['formatted_text'], - 'links': [], - 'meta': {} - } + db_page = SQLitePageInfo(row) c.execute('''SELECT target FROM links WHERE source=?''', (row['url'],)) for r in c.fetchall(): - db_page['links'].append(r['target']) + db_page.links.append(r['target']) c.execute('''SELECT page_id, name, value FROM meta WHERE page_id=?''', (row['id'],)) @@ -340,11 +344,9 @@ if value == '': value = True name = r['name'] - if name not in db_page['meta']: - db_page['meta'][name] = value - elif db_page['meta'][name] is list: - db_page['meta'][name].append(value) + if name not in db_page.meta: + db_page.meta[name] = [value] else: - db_page['meta'][name] = [db_page['meta'][name], value] + db_page.meta[name].append(value) return db_page
--- a/wikked/formatter.py Wed Feb 27 22:55:11 2013 -0800 +++ b/wikked/formatter.py Tue Mar 19 19:54:11 2013 -0700 @@ -1,7 +1,6 @@ import os import os.path import re -import types import pystache @@ -132,9 +131,7 @@ # Then, set the value on the meta dictionary, or add it to # other existing meta values with the same key. if meta_name not in ctx.meta: - ctx.meta[meta_name] = coerced_meta_value - elif isinstance(ctx.meta[meta_name], types.StringTypes): - ctx.meta[meta_name] = [ctx.meta[meta_name], coerced_meta_value] + ctx.meta[meta_name] = [coerced_meta_value] else: ctx.meta[meta_name].append(coerced_meta_value) @@ -235,12 +232,15 @@ def _formatWikiLink(self, ctx, display, url): abs_url = ctx.getAbsoluteUrl(url) ctx.out_links.append(abs_url) + return '<a class="wiki-link" data-wiki-url="%s">%s</a>' % (abs_url, display) - css_class = 'wiki-link' - if not self.wiki.pageExists(abs_url, from_db=False): - css_class += ' missing' - return '<a class="%s" data-wiki-url="%s">%s</a>' % (css_class, abs_url, display) - + @staticmethod + def parseWikiLinks(text): + urls = [] + pattern = r"<a class=\"[^\"]*\" data-wiki-url=\"(?P<url>[^\"]+)\">" + for m in re.finditer(pattern, text): + urls.append(str(m.group('url'))) + return urls class ResolveContext(object): """ The context for resolving page queries. """ @@ -266,8 +266,8 @@ self.meta = {} self.out_links = [] if page: - self.meta = dict(page.local_meta) - self.out_links = list(page.local_links) + self.meta = dict(page._getLocalMeta()) + self.out_links = list(page._getLocalLinks()) def add(self, other): self.out_links += other.out_links @@ -280,10 +280,8 @@ if key not in self.meta: self.meta[key] = val - elif self.meta[key] is list: + else: self.meta[key].append(val) - else: - self.meta[key] = [self.meta[key], val] class PageResolver(object): @@ -308,7 +306,23 @@ return self.page.wiki def run(self): - def repl(m): + if not self.ctx: + self.ctx = ResolveContext(self.page.url) + + # Resolve link states. + def repl1(m): + url = str(m.group('url')) + if self.wiki.pageExists(url): + return str(m.group()) + return '<a class="wiki-link missing" data-wiki-url="%s">' % url + + formatted_text = re.sub( + r'<a class="wiki-link" data-wiki-url="(?P<url>[^"]+)">', + repl1, + self.page._getFormattedText()) + + # Resolve queries, includes, etc. + def repl2(m): meta_name = str(m.group('name')) meta_value = str(m.group('value')) meta_opts = {} @@ -326,16 +340,15 @@ return self._runInclude(meta_opts, meta_value) return '' - if not self.ctx: - self.ctx = ResolveContext(self.page.url) - self.output = ResolveOutput(self.page) - self.output.text = re.sub(r'^<div class="wiki-(?P<name>[a-z]+)"' + self.output.text = re.sub( + r'^<div class="wiki-(?P<name>[a-z]+)"' r'(?P<opts>( data-wiki-([a-z]+)="([^"]+)")*)' r'>(?P<value>.*)</div>$', - repl, - self.page.formatted_text, + repl2, + formatted_text, flags=re.MULTILINE) + return self.output def _runInclude(self, opts, args): @@ -412,7 +425,7 @@ 'url': p.url, 'title': p.title } - tokens.update(p.local_meta) + tokens.update(p._getLocalMeta()) text += self._renderTemplate( self._valueOrPageText(parameters['__item']), tokens) @@ -434,7 +447,7 @@ # meta properties. meta_keys.append('+' + name) for key in meta_keys: - actual = page.local_meta.get(key) + actual = page._getLocalMeta().get(key) if (actual is not None and ((type(actual) is list and value in actual) or (actual == value))): @@ -450,7 +463,7 @@ else: include_meta_keys.append('__include') for key in include_meta_keys: - i = page.local_meta.get(key) + i = page._getLocalMeta().get(key) if i is not None: if (type(i) is list): include_meta_values += i
--- a/wikked/fs.py Wed Feb 27 22:55:11 2013 -0800 +++ b/wikked/fs.py Tue Mar 19 19:54:11 2013 -0700 @@ -13,6 +13,17 @@ pass +class PageInfo(object): + def __init__(self, url, path, content=None): + self.url = url + self.path = path + self.content = content + + @property + def has_content(self): + return self.content is not None + + class FileSystem(object): """ A class responsible for mapping page URLs to file-system paths, and for scanning the file-system @@ -59,11 +70,7 @@ path = self.getPhysicalPagePath(url) with codecs.open(path, 'r', encoding='utf-8') as f: content = f.read() - return { - 'url': url, - 'path': path, - 'content': content - } + return PageInfo(url, path, content) def setPage(self, path, content): with codecs.open(path, 'w', encoding='utf-8') as f: @@ -98,10 +105,7 @@ if i > 0: url += '/' url += self.slugify(part) - return { - 'url': url, - 'path': path - } + return PageInfo(url, path, None) def _getPhysicalPath(self, url, is_file): if string.find(url, '..') >= 0:
--- a/wikked/indexer.py Wed Feb 27 22:55:11 2013 -0800 +++ b/wikked/indexer.py Tue Mar 19 19:54:11 2013 -0700 @@ -44,7 +44,6 @@ self.ix = create_in(self.store_dir, schema=self._getSchema()) writer = self.ix.writer() for page in pages: - page._ensureMeta() self._indexPage(writer, page) writer.commit() @@ -72,9 +71,7 @@ to_reindex.add(indexed_path) for page in pages: - page._ensureMeta() - page_path = page._meta['path'] - if page_path in to_reindex or page_path not in already_indexed: + if page.path in to_reindex or page.path not in already_indexed: self._indexPage(writer, page) writer.commit() @@ -116,8 +113,8 @@ url=unicode(page.url), title=unicode(page.title), content=unicode(page.raw_text), - path=page._meta['path'], - time=os.path.getmtime(page._meta['path']) + path=page.path, + time=os.path.getmtime(page.path) ) def _unindexPage(self, writer, url):
--- a/wikked/page.py Wed Feb 27 22:55:11 2013 -0800 +++ b/wikked/page.py Tue Mar 19 19:54:11 2013 -0700 @@ -7,62 +7,59 @@ from formatter import PageFormatter, FormattingContext, PageResolver, CircularIncludeError +class PageData(object): + def __init__(self): + self.path = None + self.title = None + self.raw_text = None + self.formatted_text = None + self.text = None + self.local_meta = {} + self.local_links = [] + self.ext_meta = {} + self.ext_links = [] + self.has_extended_data = False + + class Page(object): """ A wiki page. """ def __init__(self, wiki, url): self.wiki = wiki self.url = url - self._meta = None - self._ext_meta = None + self._data = None @property def path(self): - self._ensureMeta() - return self._meta['path'] + self._ensureData() + return self._data.path @property def title(self): - self._ensureMeta() - return self._meta['title'] + self._ensureData() + return self._data.title @property def raw_text(self): - self._ensureMeta() - return self._meta['content'] - - @property - def formatted_text(self): - self._ensureMeta() - return self._meta['formatted'] + self._ensureData() + return self._data.raw_text @property def text(self): - self._ensureExtendedMeta() - return self._ext_meta['text'] - - @property - def local_meta(self): - self._ensureMeta() - return self._meta['meta'] + self._ensureExtendedData() + return self._data.text @property - def local_links(self): - self._ensureMeta() - return self._meta['links'] + def meta(self): + self._ensureExtendedData() + return self._data.ext_meta @property - def all_meta(self): - self._ensureExtendedMeta() - return self._ext_meta['meta'] + def links(self): + self._ensureExtendedData() + return self._data.ext_links - @property - def all_links(self): - self._ensureExtendedMeta() - return self._ext_meta['links'] - - @property - def in_links(self): + def getIncomingLinks(self): return self.wiki.db.getLinksTo(self.url) def getHistory(self): @@ -77,55 +74,71 @@ def getDiff(self, rev1, rev2): return self.wiki.scm.diff(self.path, rev1, rev2) - def _ensureMeta(self): - if self._meta is not None: + def _getFormattedText(self): + self._ensureData() + return self._data.formatted_text + + def _getLocalMeta(self): + self._ensureData() + return self._data.local_meta + + def _getLocalLinks(self): + self._ensureData() + return self._data.local_links + + def _ensureData(self): + if self._data is not None: return - self._meta = self._loadCachedMeta() - if self._meta is not None: + self._data = self._loadCachedData() + if self._data is not None: return - self._meta = self._loadOriginalMeta() - self._saveCachedMeta(self._meta) + self._data = self._loadOriginalData() + self._saveCachedData(self._data) - def _loadCachedMeta(self): + def _loadCachedData(self): return None - def _saveCachedMeta(self, meta): + def _saveCachedData(self, meta): pass - def _loadOriginalMeta(self): + def _loadOriginalData(self): + data = PageData() + # Get info from the file-system. - meta = self.wiki.fs.getPage(self.url) + page_info = self.wiki.fs.getPage(self.url) + data.path = page_info.path + data.raw_text = page_info.content # Format the page and get the meta properties. - filename = os.path.basename(meta['path']) + filename = os.path.basename(data.path) filename_split = os.path.splitext(filename) extension = filename_split[1].lstrip('.') ctx = FormattingContext(self.url, extension, slugify=Page.title_to_url) f = PageFormatter(self.wiki) - meta['formatted'] = f.formatText(ctx, meta['content']) - meta['meta'] = ctx.meta - meta['links'] = ctx.out_links + data.formatted_text = f.formatText(ctx, data.raw_text) + data.local_meta = ctx.meta + data.local_links = ctx.out_links # Add some common meta. - meta['title'] = re.sub(r'\-', ' ', filename_split[0]) - if 'title' in meta['meta']: - meta['title'] = meta['meta']['title'] + data.title = re.sub(r'\-', ' ', filename_split[0]) + if 'title' in data.local_meta: + data.title = data.local_meta['title'][0] - return meta + return data - def _ensureExtendedMeta(self): - if self._ext_meta is not None: + def _ensureExtendedData(self): + if self._data is not None and self._data.has_extended_data: return + self._ensureData() try: r = PageResolver(self) out = r.run() - self._ext_meta = {} - self._ext_meta['text'] = out.text - self._ext_meta['meta'] = out.meta - self._ext_meta['links'] = out.out_links + self._data.text = out.text + self._data.ext_meta = out.meta + self._data.ext_links = out.out_links except CircularIncludeError as cie: template_path = os.path.join( os.path.dirname(__file__), @@ -134,14 +147,10 @@ ) with open(template_path, 'r') as f: template = pystache.compile(f.read()) - self._ext_meta = { - 'text': template({ - 'message': str(cie), - 'url_trail': cie.url_trail - }), - 'meta': {}, - 'links': [] - } + self._data.text = template({ + 'message': str(cie), + 'url_trail': cie.url_trail + }) @staticmethod def title_to_url(title): @@ -174,7 +183,7 @@ raise Exception("The wiki doesn't have a database.") self.auto_update = wiki.config.get('wiki', 'auto_update') - def _loadCachedMeta(self): + def _loadCachedData(self): if self.wiki.db is None: return None db_page = self.wiki.db.getPage(self.url) @@ -182,21 +191,19 @@ return None if self.auto_update: path_time = datetime.datetime.fromtimestamp( - os.path.getmtime(db_page['path'])) - if path_time >= db_page['time']: + os.path.getmtime(db_page.path)) + if path_time >= db_page.time: return None - meta = { - 'url': self.url, - 'path': db_page['path'], - 'content': db_page['content'], - 'formatted': db_page['formatted'], - 'meta': db_page['meta'], - 'title': db_page['title'], - 'links': db_page['links'] - } - return meta + data = PageData() + data.path = db_page.path + data.title = db_page.title + data.raw_text = db_page.raw_text + data.formatted_text = db_page.formatted_text + data.local_meta = db_page.meta + data.local_links = db_page.links + return data - def _saveCachedMeta(self, meta): + def _saveCachedData(self, meta): if self.wiki.db is not None: self.wiki.logger.debug( "Updated database cache for page '%s'." % self.url)
--- a/wikked/views.py Wed Feb 27 22:55:11 2013 -0800 +++ b/wikked/views.py Tue Mar 19 19:54:11 2013 -0700 @@ -8,6 +8,7 @@ from web import app, login_manager from wiki import Page from fs import PageNotFoundError +from formatter import PageFormatter import scm @@ -23,7 +24,6 @@ def get_page_or_none(url): try: page = g.wiki.getPage(url) - page._ensureMeta() return page except PageNotFoundError: return None @@ -50,9 +50,9 @@ def get_page_meta(page, local_only=False): if local_only: - meta = dict(page.local_meta) + meta = dict(page._getLocalMeta()) else: - meta = dict(page.all_meta) + meta = dict(page.meta) meta['title'] = page.title meta['url'] = page.url for name in COERCE_META: @@ -78,11 +78,14 @@ f_info = g.wiki.fs.getPageInfo(f['path']) if f_info is None: continue - page = g.wiki.getPage(f_info['url']) - if not is_page_readable(page): - continue + page = g.wiki.getPage(f_info.url) + try: + if not is_page_readable(page): + continue + except PageNotFoundError: + pass rev_data['pages'].append({ - 'url': f_info['url'], + 'url': f_info.url, 'action': scm.ACTION_NAMES[f['action']] }) if len(rev_data['pages']) > 0: @@ -189,7 +192,7 @@ def api_get_outgoing_links(url): page = get_page_or_404(url, CHECK_FOR_READ) links = [] - for link in page.out_links: + for link in page.links: other = get_page_or_none(link) if other is not None: links.append({ @@ -199,7 +202,7 @@ else: links.append({'url': link, 'missing': True}) - result = {'meta': get_page_meta(page, True), 'out_links': links} + result = {'meta': get_page_meta(page), 'out_links': links} return make_auth_response(result) @@ -207,7 +210,7 @@ def api_get_incoming_links(url): page = get_page_or_404(url, CHECK_FOR_READ) links = [] - for link in page.in_links: + for link in page.getIncomingLinks(): other = get_page_or_none(link) if other is not None and is_page_readable(other): links.append({ @@ -217,7 +220,7 @@ else: links.append({'url': link, 'missing': True}) - result = {'meta': get_page_meta(page, True), 'in_links': links} + result = {'meta': get_page_meta(page), 'in_links': links} return make_auth_response(result) @@ -303,10 +306,34 @@ @app.route('/api/orphans') def api_special_orphans(): + run_queries = request.args.get('run_queries') + orphans = [] - for page in filter(is_page_readable, g.wiki.getPages()): - if len(page.in_links) == 0: - orphans.append({'path': page.url, 'meta': get_page_meta(page, True)}) + pages_with_queries = [] + for page in g.wiki.getPages(): + try: + if not is_page_readable(page): + continue + if len(page.getIncomingLinks()) == 0: + orphans.append({'path': page.url, 'meta': get_page_meta(page)}) + except Exception as e: + app.logger.error("Error while inspecting page: %s" % page.url) + app.logger.error(" %s" % e) + continue + if run_queries: + page_queries = page._getLocalMeta().get('query') + if page_queries is not None: + pages_with_queries.append(page) + + if run_queries: + app.logger.debug("Running queries for %d pages." % len(pages_with_queries)) + links_to_remove = set() + for page in pages_with_queries: + links = PageFormatter.parseWikiLinks(page.text) + links_to_remove |= set(links) + app.logger.debug( links_to_remove) + orphans = [o for o in orphans if o['path'] not in links_to_remove] + result = {'orphans': orphans} return make_auth_response(result) @@ -324,7 +351,7 @@ page = get_page_or_404(url, CHECK_FOR_READ) history = page.getHistory() hist_data = get_history_data(history) - result = {'url': url, 'meta': get_page_meta(page, True), 'history': hist_data} + result = {'url': url, 'meta': get_page_meta(page), 'history': hist_data} return make_auth_response(result)
--- a/wikked/wiki.py Wed Feb 27 22:55:11 2013 -0800 +++ b/wikked/wiki.py Tue Mar 19 19:54:11 2013 -0700 @@ -147,7 +147,7 @@ yield url else: for info in self.fs.getPageInfos(subdir): - yield info['url'] + yield info.url def getPages(self, subdir=None, from_db=None, factory=None): """ Gets all the pages in the wiki, or in the given sub-directory.