From 35e47358f0e3567b91da1116120c3c9fd97d8e6c Mon Sep 17 00:00:00 2001 From: Thai Tran Date: Tue, 21 Jul 2015 10:45:40 -0700 Subject: [PATCH] Fix bug where WEBROOT is not respected The WEB_ROOT setting needs to be respected rather than assuming / as the root of the application. Simiarly, we can not assume that STATIC_URL is a sub url of the WEB_ROOT. They can be configured as two indepedent url. Angular templates are loaded dynamically with Ajax, which requires an absolute base path. We define those base paths as angular constants for template use and future routing. TO TEST, follow directions at: http://docs.openstack.org/developer/horizon/topics/settings.html#webroot Co-Authored-By: Matt Borland Co-Authored-By: Shaoquan Chen Co-Authored-By: Thai Tran Change-Id: Ifcd459633682edc94b270019ce77e17d64bea22d Closes-Bug: #1451681 --- horizon/static/framework/framework.module.js | 12 ++++--- horizon/static/framework/util/http/http.js | 10 ++++-- horizon/static/framework/util/util.module.js | 27 +++++++++------ .../widgets/magic-search/magic-search.spec.js | 13 ++++--- .../framework/widgets/widgets.module.js | 34 +++++++++++-------- horizon/static/horizon/js/horizon.tables.js | 4 +-- .../templates/horizon/jasmine/jasmine.html | 4 +++ openstack_dashboard/context_processors.py | 3 ++ .../dashboard/identity/identity.module.js | 12 +++---- .../identity/projects/projects.module.js | 7 ++-- .../users/table/table.controller.spec.js | 6 ++-- .../project/images/images/tables.py | 10 +++--- .../dashboards/project/instances/tables.py | 16 ++++----- .../templates/network_topology/index.html | 3 +- openstack_dashboard/settings.py | 1 + .../static/dashboard/dashboard.module.js | 15 +++++--- .../static/dashboard/dashboard.module.spec.js | 6 ++-- .../templates/horizon/_scripts.html | 5 ++- test-shim.js | 6 ++-- 19 files changed, 117 insertions(+), 77 deletions(-) diff --git a/horizon/static/framework/framework.module.js b/horizon/static/framework/framework.module.js index 58f60d3be8..f9b1cea4b7 100644 --- a/horizon/static/framework/framework.module.js +++ b/horizon/static/framework/framework.module.js @@ -7,16 +7,20 @@ 'horizon.framework.util', 'horizon.framework.widgets' ]) - .constant('horizon.framework.basePath', '/static/framework/') - .config(frameworkConfiguration); + .config(config); - frameworkConfiguration.$inject = [ + config.$inject = [ + '$provide', '$interpolateProvider', '$httpProvider', '$windowProvider' ]; - function frameworkConfiguration($interpolateProvider, $httpProvider, $windowProvider) { + function config($provide, $interpolateProvider, $httpProvider, $windowProvider) { + + var path = $windowProvider.$get().STATIC_URL + 'framework/'; + $provide.constant('horizon.framework.basePath', path); + // Replacing the default angular symbol // allow us to mix angular with django templates $interpolateProvider.startSymbol('{$'); diff --git a/horizon/static/framework/util/http/http.js b/horizon/static/framework/util/http/http.js index 5b6b0ae9a8..70ddfc7709 100644 --- a/horizon/static/framework/util/http/http.js +++ b/horizon/static/framework/util/http/http.js @@ -21,11 +21,17 @@ limitations under the License. .module('horizon.framework.util.http', []) .service('horizon.framework.util.http.service', ApiService); - ApiService.$inject = ['$http']; + ApiService.$inject = ['$http', '$window']; - function ApiService($http) { + function ApiService($http, $window) { var httpCall = function (method, url, data, config) { + /* eslint-disable angular/ng_window_service */ + url = $window.WEBROOT + url; + /* eslint-enable angular/ng_window_service */ + + url = url.replace(/\/+/g, '/'); + if (angular.isUndefined(config)) { config = {}; } diff --git a/horizon/static/framework/util/util.module.js b/horizon/static/framework/util/util.module.js index 5a067231f9..5b7ed3d40a 100644 --- a/horizon/static/framework/util/util.module.js +++ b/horizon/static/framework/util/util.module.js @@ -1,14 +1,21 @@ (function () { 'use strict'; - angular.module('horizon.framework.util', [ - 'horizon.framework.util.bind-scope', - 'horizon.framework.util.filters', - 'horizon.framework.util.http', - 'horizon.framework.util.i18n', - 'horizon.framework.util.tech-debt', - 'horizon.framework.util.workflow', - 'horizon.framework.util.validators' - ]) - .constant('horizon.framework.util.basePath', '/static/framework/util/'); + angular + .module('horizon.framework.util', [ + 'horizon.framework.util.bind-scope', + 'horizon.framework.util.filters', + 'horizon.framework.util.http', + 'horizon.framework.util.i18n', + 'horizon.framework.util.tech-debt', + 'horizon.framework.util.workflow', + 'horizon.framework.util.validators' + ]) + .config(config); + + function config($provide, $windowProvider) { + var path = $windowProvider.$get().STATIC_URL + 'framework/util/'; + $provide.constant('horizon.framework.util.basePath', path); + } + })(); diff --git a/horizon/static/framework/widgets/magic-search/magic-search.spec.js b/horizon/static/framework/widgets/magic-search/magic-search.spec.js index 4d871e0236..287b4891b8 100644 --- a/horizon/static/framework/widgets/magic-search/magic-search.spec.js +++ b/horizon/static/framework/widgets/magic-search/magic-search.spec.js @@ -79,11 +79,14 @@ } ]; - var markup = '' + - ''; + /* eslint-disable angular/ng_window_service */ + var markup = + '' + + ''; + /* eslint-enable angular/ng_window_service */ $element = $compile(angular.element(markup))($scope); diff --git a/horizon/static/framework/widgets/widgets.module.js b/horizon/static/framework/widgets/widgets.module.js index 06494bda48..9304ea496d 100644 --- a/horizon/static/framework/widgets/widgets.module.js +++ b/horizon/static/framework/widgets/widgets.module.js @@ -1,19 +1,25 @@ (function () { 'use strict'; - angular.module('horizon.framework.widgets', [ - 'horizon.framework.widgets.help-panel', - 'horizon.framework.widgets.wizard', - 'horizon.framework.widgets.table', - 'horizon.framework.widgets.modal', - 'horizon.framework.widgets.modal-wait-spinner', - 'horizon.framework.widgets.transfer-table', - 'horizon.framework.widgets.charts', - 'horizon.framework.widgets.action-list', - 'horizon.framework.widgets.metadata-tree', - 'horizon.framework.widgets.metadata-display', - 'horizon.framework.widgets.toast' - ]) - .constant('horizon.framework.widgets.basePath', '/static/framework/widgets/'); + angular + .module('horizon.framework.widgets', [ + 'horizon.framework.widgets.help-panel', + 'horizon.framework.widgets.wizard', + 'horizon.framework.widgets.table', + 'horizon.framework.widgets.modal', + 'horizon.framework.widgets.modal-wait-spinner', + 'horizon.framework.widgets.transfer-table', + 'horizon.framework.widgets.charts', + 'horizon.framework.widgets.action-list', + 'horizon.framework.widgets.metadata-tree', + 'horizon.framework.widgets.metadata-display', + 'horizon.framework.widgets.toast' + ]) + .config(config); + + function config($provide, $windowProvider) { + var path = $windowProvider.$get().STATIC_URL + 'framework/widgets/'; + $provide.constant('horizon.framework.widgets.basePath', path); + } })(); diff --git a/horizon/static/horizon/js/horizon.tables.js b/horizon/static/horizon/js/horizon.tables.js index da18278f9b..7cb0d30501 100644 --- a/horizon/static/horizon/js/horizon.tables.js +++ b/horizon/static/horizon/js/horizon.tables.js @@ -1,4 +1,3 @@ -/* global STATIC_URL, console */ /* Namespace for core functionality related to DataTables. */ horizon.datatables = { update: function () { @@ -70,7 +69,8 @@ horizon.datatables = { var imagePath = $new_row.find('.btn-action-required').length > 0 ? "dashboard/img/action_required.png": "dashboard/img/loading.gif"; - imagePath = STATIC_URL + imagePath; + + imagePath = window.STATIC_URL + imagePath; spinner_elm.prepend( $("
") .addClass("loading_gif") diff --git a/horizon/templates/horizon/jasmine/jasmine.html b/horizon/templates/horizon/jasmine/jasmine.html index ee0ab9a817..52fb3f85ad 100644 --- a/horizon/templates/horizon/jasmine/jasmine.html +++ b/horizon/templates/horizon/jasmine/jasmine.html @@ -5,6 +5,10 @@ Jasmine Spec Runner + diff --git a/openstack_dashboard/context_processors.py b/openstack_dashboard/context_processors.py index d58fc360db..cb0dc04e82 100644 --- a/openstack_dashboard/context_processors.py +++ b/openstack_dashboard/context_processors.py @@ -53,4 +53,7 @@ def openstack(request): region in available_regions]} context['regions'] = regions + # Adding webroot access + context['WEBROOT'] = getattr(settings, "WEBROOT", "/") + return context diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/identity.module.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/identity.module.js index feae288f45..0deacabbc1 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/identity.module.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/identity.module.js @@ -29,15 +29,11 @@ 'hz.dashboard.identity.users', 'hz.dashboard.identity.projects' ]) + .config(config); - /** - * @name hz.dashboard.identity.basePath - * @description Base path for the identity dashboard - */ - .constant('hz.dashboard.identity.basePath', getBasePath()); - - function getBasePath() { - return (window.WEBROOT || '') + '/static/dashboard/identity/'; + function config($provide, $windowProvider) { + var path = $windowProvider.$get().STATIC_URL + 'dashboard/identity/'; + $provide.constant('hz.dashboard.identity.basePath', path); } })(); diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/projects/projects.module.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/projects/projects.module.js index bf513fac51..e053b2d38c 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/projects/projects.module.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/projects/projects.module.js @@ -24,10 +24,11 @@ */ angular .module('hz.dashboard.identity.projects', []) - .constant('hz.dashboard.identity.projects.basePath', basePath()); + .config(config); - function basePath() { - return (window.WEBROOT || '') + '/static/dashboard/identity/projects/'; + function config($provide, $windowProvider) { + var path = $windowProvider.$get().STATIC_URL + 'dashboard/identity/projects/'; + $provide.constant('hz.dashboard.identity.projects.basePath', path); } })(); diff --git a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/table/table.controller.spec.js b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/table/table.controller.spec.js index 664ea25ba3..2835fdc600 100644 --- a/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/table/table.controller.spec.js +++ b/openstack_dashboard/dashboards/identity/static/dashboard/identity/users/table/table.controller.spec.js @@ -44,6 +44,7 @@ var toastService; var policyAPI; var keystoneAPI; + var staticUrl; /////////////////////// @@ -61,6 +62,7 @@ policyAPI = $injector.get('horizon.openstack-service-api.policy'); keystoneAPI = $injector.get('horizon.openstack-service-api.keystone'); controller = $injector.get('$controller'); + staticUrl = $injector.get('$window').STATIC_URL; spyOn(toastService, 'add').and.callFake(fakeToast); spyOn(policyAPI, 'check').and.callFake(fakePolicy); @@ -77,7 +79,7 @@ } it('should set path properly', function() { - var path = '/static/dashboard/identity/users/table/'; + var path = staticUrl + 'dashboard/identity/users/table/'; expect(createController().path).toEqual(path); }); @@ -99,4 +101,4 @@ }); }); -})(); \ No newline at end of file +})(); diff --git a/openstack_dashboard/dashboards/project/images/images/tables.py b/openstack_dashboard/dashboards/project/images/images/tables.py index 06f6961689..319eafd5b1 100644 --- a/openstack_dashboard/dashboards/project/images/images/tables.py +++ b/openstack_dashboard/dashboards/project/images/images/tables.py @@ -60,20 +60,20 @@ class LaunchImage(tables.LinkAction): class LaunchImageNG(LaunchImage): name = "launch_image_ng" verbose_name = _("Launch") + url = "horizon:project:images:index" classes = ("btn-launch") ajax = False def __init__(self, attrs=None, **kwargs): - if attrs is None: - attrs = {"ng-controller": "LaunchInstanceModalController"} kwargs['preempt'] = True super(LaunchImage, self).__init__(attrs, **kwargs) def get_link_url(self, datum): imageId = self.table.get_object_id(datum) - clickValue = "openLaunchInstanceWizard({successUrl: " +\ - "'/project/images/', imageId: '%s'})" % (imageId) - self.attrs['ng-click'] = clickValue + url = reverse(self.url) + ngclick = "openLaunchInstanceWizard({successUrl: '%s', imageId: '%s'})" + self.attrs.update({"ng-controller": "LaunchInstanceModalController", + "ng-click": ngclick % (url, imageId)}) return "javascript:void(0);" diff --git a/openstack_dashboard/dashboards/project/instances/tables.py b/openstack_dashboard/dashboards/project/instances/tables.py index 95f51c05b5..f682a4403b 100644 --- a/openstack_dashboard/dashboards/project/instances/tables.py +++ b/openstack_dashboard/dashboards/project/instances/tables.py @@ -349,18 +349,16 @@ class LaunchLink(tables.LinkAction): class LaunchLinkNG(LaunchLink): name = "launch-ng" + url = "horizon:project:instances:index" ajax = False classes = ("btn-launch") - def __init__(self, - attrs={ - "ng-controller": "LaunchInstanceModalController", - "ng-click": "openLaunchInstanceWizard(" + - "{successUrl: '/project/instances/'})" - }, - **kwargs): - kwargs['preempt'] = True - super(LaunchLink, self).__init__(attrs, **kwargs) + def get_default_attrs(self): + url = urlresolvers.reverse(self.url) + ngclick = "openLaunchInstanceWizard({ successUrl: '%s' })" % url + self.attrs.update({'ng-controller': 'LaunchInstanceModalController', + 'ng-click': ngclick}) + return super(LaunchLinkNG, self).get_default_attrs() def get_link_url(self, datum=None): return "javascript:void(0);" diff --git a/openstack_dashboard/dashboards/project/network_topology/templates/network_topology/index.html b/openstack_dashboard/dashboards/project/network_topology/templates/network_topology/index.html index 95ecb33150..29e97fa36c 100644 --- a/openstack_dashboard/dashboards/project/network_topology/templates/network_topology/index.html +++ b/openstack_dashboard/dashboards/project/network_topology/templates/network_topology/index.html @@ -29,7 +29,8 @@
{% if launch_instance_allowed %} {% if show_ng_launch %} - {% if instance_quota_exceeded %}{% trans "Launch Instance (Quota exceeded)"%}{% else %}{% trans "Launch Instance"%}{% endif %} + {% url 'horizon:project:network_topology:index' as networkUrl %} + {% if instance_quota_exceeded %}{% trans "Launch Instance (Quota exceeded)"%}{% else %}{% trans "Launch Instance"%}{% endif %} {% endif %} {% if instance_quota_exceeded %}{% trans "Launch Instance (Quota exceeded)"%}{% else %}{% trans "Launch Instance"%}{% endif %} {% endif %} diff --git a/openstack_dashboard/settings.py b/openstack_dashboard/settings.py index 4835ec7e77..a8d570a09a 100644 --- a/openstack_dashboard/settings.py +++ b/openstack_dashboard/settings.py @@ -364,6 +364,7 @@ POLICY_CHECK_FUNCTION = policy_backend.check # Add HORIZON_CONFIG to the context information for offline compression COMPRESS_OFFLINE_CONTEXT = { + 'WEBROOT': WEBROOT, 'STATIC_URL': STATIC_URL, 'HORIZON_CONFIG': HORIZON_CONFIG, } diff --git a/openstack_dashboard/static/dashboard/dashboard.module.js b/openstack_dashboard/static/dashboard/dashboard.module.js index e2280cfd47..55a7bc97b9 100644 --- a/openstack_dashboard/static/dashboard/dashboard.module.js +++ b/openstack_dashboard/static/dashboard/dashboard.module.js @@ -1,11 +1,16 @@ (function () { 'use strict'; - angular.module('hz.dashboard', [ - 'hz.dashboard.launch-instance', - 'hz.dashboard.tech-debt' - ]) + angular + .module('hz.dashboard', [ + 'hz.dashboard.launch-instance', + 'hz.dashboard.tech-debt' + ]) + .config(config); - .constant('dashboardBasePath', '/static/dashboard/'); + function config($provide, $windowProvider) { + var path = $windowProvider.$get().STATIC_URL + 'dashboard/'; + $provide.constant('dashboardBasePath', path); + } })(); diff --git a/openstack_dashboard/static/dashboard/dashboard.module.spec.js b/openstack_dashboard/static/dashboard/dashboard.module.spec.js index b72b7b8bbf..80590e29cf 100644 --- a/openstack_dashboard/static/dashboard/dashboard.module.spec.js +++ b/openstack_dashboard/static/dashboard/dashboard.module.spec.js @@ -24,18 +24,20 @@ describe('hz.dashboard:constant:dashboardBasePath', function () { var dashboardBasePath; + var staticUrl; beforeEach(module('hz.dashboard')); beforeEach(inject(function ($injector) { dashboardBasePath = $injector.get('dashboardBasePath'); + staticUrl = $injector.get('$window').STATIC_URL; })); it('should be defined', function () { expect(dashboardBasePath).toBeDefined(); }); - it('should equal to "/static/dashboard/"', function () { - expect(dashboardBasePath).toEqual('/static/dashboard/'); + it('should get set correctly', function () { + expect(dashboardBasePath).toEqual(staticUrl + 'dashboard/'); }); }); diff --git a/openstack_dashboard/templates/horizon/_scripts.html b/openstack_dashboard/templates/horizon/_scripts.html index a3498dcd42..2a07e11351 100644 --- a/openstack_dashboard/templates/horizon/_scripts.html +++ b/openstack_dashboard/templates/horizon/_scripts.html @@ -8,7 +8,10 @@ {% comment %} Compress jQuery, Angular, Plugins, Bootstrap, Hogan.js and Horizon-specific JS. {% endcomment %} {% compress js %} - + diff --git a/test-shim.js b/test-shim.js index 81efe92b97..5b364ba31a 100644 --- a/test-shim.js +++ b/test-shim.js @@ -90,9 +90,7 @@ var horizonPlugInModules = []; globals.npgettext = django.npgettext; globals.interpolate = django.interpolate; globals.get_format = django.get_format; + globals.STATIC_URL = '/static/'; + globals.WEBROOT = '/'; }(this)); - - - -