# HG changeset patch # User Ludovic Chabant # Date 1386260575 28800 # Node ID f47b047c9414b8b8fbf8f0cda217230d1d22f9fd # Parent 96e1acf033684cccc51861a17c043986869395cb Changed URL schemes around meta pages: - They're now handled the same as normal pages. - Added endpoint to get the main page. - Reduced a bit the amount of redundant unquoting/URL massaging. diff -r 96e1acf03368 -r f47b047c9414 static/js/wikked/app.js --- a/static/js/wikked/app.js Tue Dec 03 09:46:43 2013 -0800 +++ b/static/js/wikked/app.js Thu Dec 05 08:22:55 2013 -0800 @@ -64,9 +64,7 @@ routes: { 'read/*path': "readPage", '': "readMainPage", - 'meta/:name/*path': "readMetaPage", 'edit/*path': "editPage", - 'edit_meta/:name/*path':"editMetaPage", 'changes/*path': "showPageHistory", 'inlinks/*path': "showIncomingLinks", 'revision/*path/:rev': "readPageRevision", @@ -94,13 +92,6 @@ readMainPage: function() { this.readPage(''); }, - readMetaPage: function(name, path) { - var view = new Views.MetaPageView({ - model: new Models.MetaPageModel({ name: name, path: path }) - }); - this.viewManager.switchView(view); - this.navigate('/meta/' + name + '/' + path); - }, editPage: function(path) { var view = new Views.PageEditView({ model: new Models.PageEditModel({ path: path }) @@ -108,13 +99,6 @@ this.viewManager.switchView(view); this.navigate('/edit/' + path); }, - editMetaPage: function(name, path) { - var view = new Views.MetaPageEditView({ - model: new Models.MetaPageEditModel({ name: name, path: path }) - }); - this.viewManager.switchView(view); - this.navigate('/edit_meta/' + name + '/' + path); - }, showPageHistory: function(path) { var view = new Views.PageHistoryView({ model: new Models.PageHistoryModel({ path: path }) diff -r 96e1acf03368 -r f47b047c9414 static/js/wikked/handlebars.js --- a/static/js/wikked/handlebars.js Tue Dec 03 09:46:43 2013 -0800 +++ b/static/js/wikked/handlebars.js Thu Dec 05 08:22:55 2013 -0800 @@ -107,7 +107,7 @@ }); Handlebars.registerHelper('get_cat_url', function(url, options) { url = url.toString(); - return '/#/meta/category/' + url.replace(/^\//, ''); + return '/#/read/category:' + url.replace(/^\//, ''); }); }); diff -r 96e1acf03368 -r f47b047c9414 static/js/wikked/models.js --- a/static/js/wikked/models.js Tue Dec 03 09:46:43 2013 -0800 +++ b/static/js/wikked/models.js Thu Dec 05 08:22:55 2013 -0800 @@ -16,7 +16,7 @@ idAttribute: 'path', defaults: function() { return { - path: "main-page", + path: "", action: "read", user: false }; @@ -52,7 +52,7 @@ }, _onChangePath: function(path) { this.set({ - url_home: '/#/read/main-page', + url_home: '/', url_read: '/#/read/' + path, url_edit: '/#/edit/' + path, url_hist: '/#/changes/' + path, @@ -249,16 +249,6 @@ } }); - var MetaPageModel = exports.MetaPageModel = MasterPageModel.extend({ - action: 'read', - url: function() { - return '/api/read_meta/' + this.get('name') + '/' + this.get('path'); - }, - checkStatePath: function() { - return this.getMeta('url'); - } - }); - var PageSourceModel = exports.PageSourceModel = MasterPageModel.extend({ urlRoot: '/api/raw/', action: 'source' @@ -289,31 +279,6 @@ } }); - var MetaPageEditModel = exports.MetaPageEditModel = PageEditModel.extend({ - action: 'edit', - url: function() { - return '/api/edit_meta/' + this.get('name') + '/' + this.get('path'); - }, - initialize: function() { - MetaPageEditModel.__super__.initialize.apply(this, arguments); - this.on('change:name', function(model, name) { - model._onChangeName(name); - }); - }, - _onChangeName: function(name) { - this.set('url_read', name + '/' + this.get('path')); - }, - _onEditSuccess: function() { - this.navigate( - '/meta/' + this.get('name') + '/' + this.get('path'), - { trigger: true } - ); - }, - _getReadPath: function(path) { - return '/#/meta/' + this.get('name') + '/' + path; - } - }); - var PageHistoryModel = exports.PageHistoryModel = MasterPageModel.extend({ urlRoot: '/api/history/', action: 'history', diff -r 96e1acf03368 -r f47b047c9414 static/js/wikked/views.js --- a/static/js/wikked/views.js Tue Dec 03 09:46:43 2013 -0800 +++ b/static/js/wikked/views.js Thu Dec 05 08:22:55 2013 -0800 @@ -257,9 +257,9 @@ var meta_name = jel.attr('data-wiki-meta'); var meta_value = jel.attr('data-wiki-value'); if (jel.hasClass('missing') || jel.attr('data-action') == 'edit') - jel.attr('href', '/#/edit_meta/' + meta_name + '/' + meta_value); + jel.attr('href', '/#/edit/' + meta_name + ':' + meta_value); else - jel.attr('href', '/#/meta/' + meta_name + '/' + meta_value); + jel.attr('href', '/#/read/' + meta_name + ':' + meta_value); }); // If we've already rendered the content, see if we need to display a // warning about the page's state. @@ -311,10 +311,6 @@ } }); - var MetaPageView = exports.MetaPageView = PageReadView.extend({ - defaultTemplateSource: tplMetaPage - }); - var PageEditView = exports.PageEditView = MasterPageView.extend({ defaultTemplateSource: tplEditPage, dispose: function() { @@ -453,9 +449,6 @@ } }); - var MetaPageEditView = exports.MetaPageEditView = PageEditView.extend({ - }); - var PageHistoryView = exports.PageHistoryView = MasterPageView.extend({ defaultTemplateSource: tplHistoryPage, events: { diff -r 96e1acf03368 -r f47b047c9414 wikked/utils.py --- a/wikked/utils.py Tue Dec 03 09:46:43 2013 -0800 +++ b/wikked/utils.py Thu Dec 05 08:22:55 2013 -0800 @@ -5,6 +5,9 @@ from xml.sax.saxutils import escape, unescape +endpoint_regex = re.compile(r'(\w[\w\d]*)\:(.*)') + + class PageNotFoundError(Exception): """ An error raised when no physical file is found for a given URL. @@ -63,6 +66,15 @@ return abs_url +def split_page_url(url): + m = endpoint_regex.match(url) + if m is None: + return (None, url) + endpoint = unicode(m.group(1)) + path = unicode(m.group(2)) + return (endpoint, path) + + def get_meta_name_and_modifiers(name): """ Strips a meta name from any leading modifiers like `__` or `+` and returns both as a tuple. If no modifier was found, the diff -r 96e1acf03368 -r f47b047c9414 wikked/views.py --- a/wikked/views.py Tue Dec 03 09:46:43 2013 -0800 +++ b/wikked/views.py Thu Dec 05 08:22:55 2013 -0800 @@ -1,4 +1,3 @@ -import re import time import urllib import string @@ -13,6 +12,7 @@ from fs import PageNotFoundError from formatter import PageFormatter, FormattingContext from scm.base import STATE_NAMES, ACTION_NAMES +from utils import split_page_url DONT_CHECK = 0 @@ -48,37 +48,44 @@ def url_from_viewarg(url): url = urllib.unquote(url) - m = re.match(r'(\w[\w\d]+)\:(.*)', url) - if m: - endpoint = str(m.group(1)) - path = string.lstrip(str(m.group(2)), '/') - return '%s:/%s' % (endpoint, path) - return '/' + string.lstrip(url, '/') + endpoint, path = split_page_url(url) + if endpoint: + return u'%s:/%s' % (endpoint, path) + return u'/' + path + + +def split_url_from_viewarg(url): + url = urllib.unquote(url) + endpoint, path = split_page_url(url) + value = string.rsplit(path, '/', 1)[-1] + return (endpoint, value, u'/' + path) def make_page_title(url): return url[1:] -def get_page_or_none(url, force_resolve=False): - url = url_from_viewarg(url) +def get_page_or_none(url, convert_url=True, check_perms=DONT_CHECK, force_resolve=False): + if convert_url: + url = url_from_viewarg(url) try: page = g.wiki.getPage(url) - if force_resolve: - page._force_resolve = True - page._ensureData() - return page except PageNotFoundError: return None + if force_resolve: + page._force_resolve = True + if check_perms == CHECK_FOR_READ and not is_page_readable(page): + abort(401) + elif check_perms == CHECK_FOR_WRITE and not is_page_writable(page): + abort(401) -def get_page_or_404(url, check_perms=DONT_CHECK, force_resolve=False): - page = get_page_or_none(url, force_resolve) + return page + + +def get_page_or_404(url, convert_url=True, check_perms=DONT_CHECK, force_resolve=False): + page = get_page_or_none(url, convert_url, check_perms, force_resolve) if page is not None: - if check_perms == CHECK_FOR_READ and not is_page_readable(page): - abort(401) - elif check_perms == CHECK_FOR_WRITE and not is_page_writable(page): - abort(401) return page app.logger.error("No such page: " + url) abort(404) @@ -157,7 +164,7 @@ def get_edit_page(url, default_title=None, custom_data=None): - page = get_page_or_none(url) + page = get_page_or_none(url, convert_url=False) if page is None: result = { 'meta': { @@ -183,7 +190,7 @@ def do_edit_page(url, default_message): - page = get_page_or_none(url) + page = get_page_or_none(url, convert_url=False) if page and not is_page_writable(page): app.logger.error("Page '%s' is not writable for user '%s'." % (url, current_user.get_id())) abort(401) @@ -261,50 +268,50 @@ @app.route('/api/read/') def api_read_main_page(): - return api_read_page(g.wiki.main_page_url) + return api_read_page(g.wiki.main_page_url.lstrip('/')) @app.route('/api/read/') def api_read_page(url): - page = get_page_or_404( - url, + #TODO: remove redundant quoting/spliting/unquoting around here. + endpoint, value, path = split_url_from_viewarg(url) + if endpoint is None: + # Normal page. + page = get_page_or_404( + path, + convert_url=False, + check_perms=CHECK_FOR_READ, + force_resolve=('force_resolve' in request.args)) + + result = {'meta': get_page_meta(page), 'text': page.text} + return make_auth_response(result) + + # Meta listing page. + meta_page_url = '%s:%s' % (endpoint, path) + info_page = get_page_or_none( + meta_page_url, + convert_url=False, check_perms=CHECK_FOR_READ, force_resolve=('force_resolve' in request.args)) - result = {'meta': get_page_meta(page), 'text': page.text} - return make_auth_response(result) - -@app.route('/api/raw/') -def api_read_page_raw(url): - page = get_page_or_404(url, CHECK_FOR_READ) - result = {'meta': get_page_meta(page), 'text': page.raw_text} - return make_auth_response(result) - - -@app.route('/api/read_meta//') -def api_read_meta_page(name, value): - quoted_value = value - value = urllib.unquote(value) - - query = {name: [value]} + # Get the list of pages to show here. + query = {endpoint: [value]} pages = g.wiki.getPages(meta_query=query) tpl_data = { - 'name': name, + 'name': endpoint, 'value': value, - 'safe_value': quoted_value, + 'safe_value': urllib.quote(value), 'pages': [get_page_meta(p) for p in pages] + # TODO: skip pages that are forbidden for the current user } - - meta_page_url = '%s:/%s' % (name, value) - info_page = get_page_or_none( - meta_page_url, - force_resolve=('force_resolve' in request.args)) if info_page: tpl_data['info_text'] = info_page.text + # Render the final page as the list of pages matching the query, + # under either a default text, or the text from the meta page. text = render_template('meta_page.html', **tpl_data) result = { - 'meta_query': name, + 'meta_query': endpoint, 'meta_value': value, 'query': query, 'meta': { @@ -319,12 +326,19 @@ return make_auth_response(result) +@app.route('/api/raw/') +def api_read_page_raw(url): + page = get_page_or_404(url, check_perms=CHECK_FOR_READ) + result = {'meta': get_page_meta(page), 'text': page.raw_text} + return make_auth_response(result) + + @app.route('/api/revision/') def api_read_page_rev(url): rev = request.args.get('rev') if rev is None: abort(400) - page = get_page_or_404(url, CHECK_FOR_READ) + page = get_page_or_404(url, check_perms=CHECK_FOR_READ) page_rev = page.getRevision(rev) meta = dict(get_page_meta(page, True), rev=rev) result = {'meta': meta, 'text': page_rev} @@ -348,7 +362,7 @@ rev2 = request.args.get('rev2') if rev1 is None: abort(400) - page = get_page_or_404(url, CHECK_FOR_READ) + page = get_page_or_404(url, check_perms=CHECK_FOR_READ) diff = page.getDiff(rev1, rev2) if 'raw' not in request.args: lexer = get_lexer_by_name('diff') @@ -364,7 +378,7 @@ @app.route('/api/state/') def api_get_state(url): - page = get_page_or_404(url, CHECK_FOR_READ) + page = get_page_or_404(url, check_perms=CHECK_FOR_READ) state = page.getState() return make_auth_response({ 'meta': get_page_meta(page, True), @@ -374,7 +388,7 @@ @app.route('/api/outlinks/') def api_get_outgoing_links(url): - page = get_page_or_404(url, CHECK_FOR_READ) + page = get_page_or_404(url, check_perms=CHECK_FOR_READ) links = [] for link in page.links: other = get_page_or_none(link) @@ -392,7 +406,7 @@ @app.route('/api/inlinks/') def api_get_incoming_links(url): - page = get_page_or_404(url, CHECK_FOR_READ) + page = get_page_or_404(url, check_perms=CHECK_FOR_READ) links = [] for link in page.getIncomingLinks(): other = get_page_or_none(link) @@ -410,31 +424,31 @@ @app.route('/api/edit/', methods=['GET', 'POST']) def api_edit_page(url): - url = url_from_viewarg(url) - if request.method == 'GET': - return get_edit_page(url) - - default_message = 'Edited ' + url - return do_edit_page(url, default_message) - - -@app.route('/api/edit_meta//', methods=['GET', 'POST']) -def api_edit_meta_page(name, value): - value = urllib.unquote(value) - meta_page_url = '%s:/%s' % (name, value) + endpoint, value, path = split_url_from_viewarg(url) if request.method == 'GET': - custom_data = { - 'meta_query': name, - 'meta_value': value - } + url = path + default_title = None + custom_data = None + if endpoint is not None: + url = u'%s:%s' % (endpoint, path) + default_title = u'%s: %s' % (endpoint, value) + custom_data = { + 'meta_query': endpoint, + 'meta_value': value + } + return get_edit_page( - meta_page_url, - default_title=('%s: %s' % (name, value)), + url, + default_title=default_title, custom_data=custom_data) - default_message = 'Edited %s %s' % (name, value) - return do_edit_page(meta_page_url, default_message) + url = path + default_message = u'Edited ' + url + if endpoint is not None: + url = u'%s:%s' % (endpoint, path) + default_message = u'Edited %s %s' % (endpoint, value) + return do_edit_page(url, default_message) @app.route('/api/revert/', methods=['POST']) @@ -507,7 +521,7 @@ @app.route('/api/history/') def api_page_history(url): - page = get_page_or_404(url, CHECK_FOR_READ) + page = get_page_or_404(url, check_perms=CHECK_FOR_READ) history = page.getHistory() hist_data = get_history_data(history) result = {'url': url, 'meta': get_page_meta(page), 'history': hist_data}