Commit 5834d68a authored by Jan Čermák's avatar Jan Čermák

refactoring of reverse() - allow moving script root to non-root location

parent f698b9f1
......@@ -14,23 +14,25 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from bottle import Bottle, request, template
import bottle
from collections import OrderedDict
from datetime import datetime
import os
import logging
from urlparse import urlunsplit
from bottle import Bottle, request, template
import bottle
from config_handlers import *
from foris import gettext_dummy as gettext, make_notification_title, ugettext as _
import logging
from nuci import client
from nuci.client import filters
from nuci.exceptions import ConfigRestoreError
from utils import login_required
from collections import OrderedDict
from utils import messages
from utils.bottle_csrf import CSRFPlugin
from utils.routing import reverse
logger = logging.getLogger(__name__)
......@@ -206,11 +208,14 @@ class MaintenanceConfigPage(ConfigPageMixin, MaintenanceHandler):
result = super(MaintenanceConfigPage, self).save(no_messages=True, *args, **kwargs)
new_ip = self.form.callback_results.get('new_ip')
if new_ip:
# rebuild current URL with new IP
old_urlparts = bottle.request.urlparts
new_url = urlunsplit((old_urlparts.scheme, new_ip, old_urlparts.path, "", ""))
messages.success(_("Configuration was successfully restored. After installing "
"updates and rebooting, router will be available at "
"<a href=\"//%(new_ip)s\">%(new_ip)s</a> in local "
"updates and rebooting you can return to this page at "
"<a href=\"%(new_url)s\">%(new_url)s</a> in local "
"network. Please wait a while until router automatically "
"restarts.") % dict(new_ip=new_ip))
"restarts.") % dict(new_url=new_url))
elif result:
messages.success(_("Configuration was successfully restored. Please wait a while "
"for installation of updates and automatic restart of the "
......@@ -381,7 +386,7 @@ def config_action_post(page_name, action):
raise bottle.HTTPError(404, "Unknown action.")
@app.route("/<page_name:re:.+>/ajax")
@app.route("/<page_name:re:.+>/ajax", name="config_ajax")
@login_required
def config_ajax(page_name):
action = request.GET.get("action")
......
......@@ -117,7 +117,7 @@ def change_lang(lang):
backlink = bottle.request.GET.get('backlink')
if backlink and is_safe_redirect(backlink, bottle.request.get_header('host')):
bottle.redirect(backlink)
bottle.redirect("/")
bottle.redirect(reverse("index"))
else:
raise bottle.HTTPError(404, "Language '%s' is not available." % lang)
......@@ -180,7 +180,7 @@ def login():
redirect = "/?next=%s" % next
if is_safe_redirect(redirect, bottle.request.get_header('host')):
bottle.redirect(redirect)
bottle.redirect("/")
bottle.redirect(reverse("index"))
@bottle.route("/logout", name="logout")
......@@ -188,7 +188,7 @@ def logout():
session = bottle.request.environ["beaker.session"]
if "user_authenticated" in session:
session.delete()
bottle.redirect("/")
bottle.redirect(reverse("index"))
@bottle.route('/static/<filename:re:.*>', name="static")
......@@ -261,16 +261,21 @@ def make_notification_title(notification):
)
def init_foris_app(app):
def init_foris_app(app, prefix):
"""
Initializes Foris application - use this method to apply properties etc.
that should be set to main app and all the mounted apps (i.e. to the
Bottle() instances).
:param app: instance of bottle application to mount
:param prefix: prefix which has been used to mount the application
"""
app.catchall = False # catched by LoggingMiddleware
app.catchall = False # caught by LoggingMiddleware
app.error_handler[403] = foris_403_handler
app.add_hook('after_request', clickjacking_protection)
app.add_hook('after_request', disable_caching)
app.config['prefix'] = prefix
def get_arg_parser():
......@@ -321,11 +326,12 @@ def prepare_main_app(args):
app.config["no_auth"] = True
# set custom app attributes for main app and all mounted apps
init_foris_app(app)
init_foris_app(app, None)
for route in app.routes:
if route.config.get("mountpoint"):
mounted = route.config['mountpoint.target']
init_foris_app(mounted)
prefix = route.config['mountpoint.prefix']
init_foris_app(mounted, prefix)
if args.nucipath:
client.StaticNetconfConnection.set_bin_path(args.nucipath)
......
......@@ -30,10 +30,22 @@ var Foris = {
}
};
// do some magic to find CGI SCRIPT_NAME - must be run exactly when script is parsed
(function (window, Foris) {
try {
var scripts = window.document.getElementsByTagName('script');
var pathname = extractPathName(scripts[scripts.length - 1].src);
Foris.scriptname = pathname.substr(0, pathname.indexOf("/static"));
} catch (e) {
Foris.scriptname = "";
}
})(window, Foris);
Foris.initialize = function () {
$(document).on("change", ".has-requirements", function () {
var input = $(this);
input.parent().append('<img src="/static/img/icon-loading.gif" class="field-loading" alt="' + Foris.messages.loading + '">');
input.parent().append('<img src="' + Foris.scriptname + '/static/img/icon-loading.gif" class="field-loading" alt="' + Foris.messages.loading + '">');
Foris.updateForm(input.closest("form"));
});
......@@ -90,7 +102,7 @@ Foris.initLanChangeDetection = function () {
$(document).on("submit", "#main-form", function () {
// if the value really changed from the default
if (lanField.defaultValue != lanField.value) {
var newLocation = document.location.protocol + "//" + lanField.value + "/?next=" + document.location.pathname;
var newLocation = document.location.protocol + "//" + lanField.value + Foris.scriptname + "/?next=" + document.location.pathname;
$(".config-description, .wizard-description").after('<div class="message info">' + Foris.messages.lanIpChanged.replace(/%IP_ADDR%/g, lanField.value).replace(/%NEW_LOC%/g, newLocation) + '</div>');
// if the page was accessed from the old IP address, wait 10 seconds and do a redirect
window.setTimeout(function () {
......@@ -166,7 +178,7 @@ Foris.updateForm = function (form) {
Foris.callAjaxAction = function (wizardStep, action, timeout) {
timeout = timeout || 0;
return $.ajax({
url:"/wizard/step/" + wizardStep + "/ajax",
url: Foris.scriptname + "/wizard/step/" + wizardStep + "/ajax",
data: {action: action},
timeout: timeout
});
......@@ -417,7 +429,7 @@ Foris.initNotifications = function (csrf_token) {
$(".notification .dismiss").on("click", function(e) {
e.preventDefault();
var id = $(this).data("id");
$.post("/config/notifications/dismiss",
$.post(Foris.scriptname + "/config/notifications/dismiss",
{
message_ids: [id],
csrf_token: csrf_token
......@@ -451,6 +463,13 @@ Foris.initNotificationTestAlert = function () {
});
};
function extractPathName(src) {
var a = document.createElement("a");
a.href = src;
return a.pathname;
}
$(document).ready(function () {
Foris.initialize();
});
......@@ -57,8 +57,8 @@
var self = $(this);
e.preventDefault();
self.attr("disabled", "disabled");
self.after('<img src="/static/img/icon-loading.gif" id="registration-code-loader" alt="' + Foris.messages.loading +'">');
$.get("/config/about/ajax", {action: "registration_code"})
self.after('<img src="{{ static("img/icon-loading.gif") }}" id="registration-code-loader" alt="' + Foris.messages.loading +'">');
$.get('{{ url("config_ajax", page_name="about") }}', {action: "registration_code"})
.done(function(response) {
if (response.success) {
$("#registration-code").text(response.data).show();
......
......@@ -58,8 +58,8 @@
var self = $(this);
e.preventDefault();
self.attr("disabled", "disabled");
self.after('<img src="/static/img/icon-loading.gif" id="connection-test-loader" alt="' + Foris.messages.loading + '">');
$.get("/config/dns/ajax", {action: "check-connection"})
self.after('<img src="{{ static("img/icon-loading.gif") }}" id="connection-test-loader" alt="' + Foris.messages.loading + '">');
$.get('{{ url("config_ajax", page_name="dns") }}', {action: "check-connection"})
.done(function(response) {
if (response.success) {
for (var key in response.check_results) {
......
......@@ -24,6 +24,7 @@ from nuci.client import edit_uci_config
from nuci.modules import uci_raw
from utils import print_model, login_required
from utils.bottle_csrf import CSRFPlugin
from utils.routing import reverse
from validators import NotEmpty, RegExp
......@@ -126,7 +127,7 @@ def edit_post(node):
if form.validates(request.POST):
form.save_to_model(node_model)
edit_uci_config(node_model)
bottle.redirect("/uci/?done")
bottle.redirect(reverse("uci_index") + "?done")
return dict(form=form, node_path=node)
......@@ -194,7 +195,7 @@ def create_post(node):
parent.add(new_element)
print_model(new_element)
edit_uci_config(new_element)
bottle.redirect("/uci/")
bottle.redirect(reverse("uci_index"))
@app.get("/<node:re:\w+(\.\w+)*>/remove", name="uci_remove")
......@@ -205,10 +206,10 @@ def remove(node):
node_model.operation = "remove"
try:
edit_uci_config(node_model)
bottle.redirect("/uci/?done")
bottle.redirect(reverse("uci_index") + "?done")
except RPCError, e:
logger.error(e.message)
bottle.redirect("/uci/?error")
bottle.redirect(reverse("uci_index") + "?error")
@app.get("/<node:re:\w+(\.\w+)*>/debug", name="uci_debug")
......
......@@ -21,6 +21,8 @@ from functools import wraps
import logging
from xml.etree import cElementTree as ET
from .routing import reverse
logger = logging.getLogger("foris.utils")
......@@ -31,7 +33,7 @@ def is_user_authenticated():
def redirect_unauthenticated(redirect_url=None):
redirect_url = redirect_url or "/"
redirect_url = redirect_url or reverse("index")
no_auth = bottle.default_app().config.get("no_auth", False)
if not no_auth and not is_user_authenticated():
from foris import ugettext as _
......
......@@ -21,18 +21,22 @@ logger = logging.getLogger("utils.routing")
def reverse(name, **kargs):
# Bottle sometimes builds URLs with two slashes
# and we do not build absolute URLs anyway
clean = lambda x: x.replace("//", "/")
script_name = bottle.request.script_name
prefix = bottle.request.app.config.get("prefix")
if prefix:
path_depth = len([p for p in prefix.split('/') if p])
script_name, path_info = bottle.path_shift(script_name, "/", -path_depth)
try:
return clean(bottle.app().router.build(name, **kargs))
path = bottle.app().router.build(name, **kargs)
return "".join([script_name.rstrip("/"), path])
except bottle.RouteBuildError:
for route in bottle.app().routes:
if route.config.get("mountpoint"):
config = route.config
try:
return clean("%s%s" % (config['mountpoint.prefix'].rstrip("/"),
config['mountpoint.target'].router.build(name, **kargs)))
prefix = config['mountpoint.prefix'].rstrip("/")
path = config['mountpoint.target'].router.build(name, **kargs)
return "".join([script_name.rstrip("/"), prefix, path])
except bottle.RouteBuildError as e:
if str(e).startswith("Missing URL"):
raise e
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment