aboutsummaryrefslogtreecommitdiffstats
path: root/moon_dashboard
diff options
context:
space:
mode:
authorThomas Duval <thomas.duval@orange.com>2018-10-05 16:54:37 +0200
committerThomas Duval <thomas.duval@orange.com>2018-10-05 16:58:48 +0200
commit2e35a7e46f0929438c1c206e3116caa829f07dc6 (patch)
tree759a83b3dfefe70faeada1c3af7377f4cd89b8eb /moon_dashboard
parent2dbe655587ca98b67c1a3e3798c63fd47229adc0 (diff)
Update code to 4.6 official version
Change-Id: Ibd0da0e476e24b2685f54693efc11f7a58d40a62
Diffstat (limited to 'moon_dashboard')
-rw-r--r--moon_dashboard/Dockerfile10
-rw-r--r--moon_dashboard/moon/api/__init__.py0
-rw-r--r--moon_dashboard/moon/api/moon_api.py0
-rwxr-xr-xmoon_dashboard/moon/static/moon/js/moon.module.js2
-rwxr-xr-xmoon_dashboard/moon/static/moon/js/util.service.js8
-rw-r--r--moon_dashboard/moon/static/moon/model/model.controller.js150
-rw-r--r--moon_dashboard/moon/static/moon/model/model.html10
-rwxr-xr-xmoon_dashboard/moon/static/moon/model/model.service.js5
-rw-r--r--moon_dashboard/moon/static/moon/pdp/pdp.controller.js12
-rw-r--r--moon_dashboard/moon/static/moon/policy/policy.controller.js76
-rw-r--r--moon_dashboard/moon/static/moon/policy/policy.html74
-rwxr-xr-xmoon_dashboard/moon/static/moon/policy/policy.service.js122
-rwxr-xr-xmoon_dashboard/moon/static/moon/policy/policy.service.spec.js151
-rw-r--r--moon_dashboard/moon/static/moon/scss/moon.scss4
-rw-r--r--moon_dashboard/run.sh38
-rw-r--r--moon_dashboard/setup.cfg2
16 files changed, 560 insertions, 104 deletions
diff --git a/moon_dashboard/Dockerfile b/moon_dashboard/Dockerfile
index 8f997fe1..790a2b21 100644
--- a/moon_dashboard/Dockerfile
+++ b/moon_dashboard/Dockerfile
@@ -8,19 +8,21 @@ LABEL Url="https://wiki.opnfv.org/display/moon/Moon+Project+Proposal"
ENV MANAGER_HOST="127.0.0.1"
ENV MANAGER_PORT=30001
ENV KEYSTONE_HOST="127.0.0.1"
-ENV KEYSTONE_PORT=30005
+ENV KEYSTONE_PORT=5000
ENV OPENSTACK_HOST="127.0.0.1"
-ENV OPENSTACK_KEYSTONE_URL="http://${KEYSTONE_HOST}:${KEYSTONE_PORT}/v2.0"
+ENV OPENSTACK_KEYSTONE_URL="http://${KEYSTONE_HOST}:${KEYSTONE_PORT}/identity/v3"
+ENV SERVER_IP_ADDR="0.0.0.0"
USER root
WORKDIR /root/
ADD . /root
-RUN git clone https://git.openstack.org/openstack/horizon
+RUN [ -d horizon ] || git clone https://git.openstack.org/openstack/horizon
WORKDIR /root/horizon
+# RUN pip install --no-cache-dir pip
RUN pip install --no-cache-dir -c http://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt .
RUN cp openstack_dashboard/local/local_settings.py.example openstack_dashboard/local/local_settings.py
@@ -31,4 +33,6 @@ WORKDIR /root/
RUN cp -v moon/enabled/_32000_moon.py horizon/openstack_dashboard/local/enabled/_32000_moon.py
RUN cp -rv moon/ horizon/openstack_dashboard/dashboards/
+EXPOSE 8000
+
CMD ["/bin/sh", "/root/run.sh"] \ No newline at end of file
diff --git a/moon_dashboard/moon/api/__init__.py b/moon_dashboard/moon/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/moon_dashboard/moon/api/__init__.py
diff --git a/moon_dashboard/moon/api/moon_api.py b/moon_dashboard/moon/api/moon_api.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/moon_dashboard/moon/api/moon_api.py
diff --git a/moon_dashboard/moon/static/moon/js/moon.module.js b/moon_dashboard/moon/static/moon/js/moon.module.js
index ed56ec2a..c8b86439 100755
--- a/moon_dashboard/moon/static/moon/js/moon.module.js
+++ b/moon_dashboard/moon/static/moon/js/moon.module.js
@@ -23,7 +23,7 @@
.module('moon', [
'ngResource',
]).constant('moon.URI', {
- API: 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}',
+ API: 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}',
})
})();
diff --git a/moon_dashboard/moon/static/moon/js/util.service.js b/moon_dashboard/moon/static/moon/js/util.service.js
index 18ae901d..29680a43 100755
--- a/moon_dashboard/moon/static/moon/js/util.service.js
+++ b/moon_dashboard/moon/static/moon/js/util.service.js
@@ -117,8 +117,12 @@
},
displayErrorFunction: function displayErrorFunction(message) {
- return function() {
- toast.add('error', gettext(message));
+ return function(response) {
+ var text = gettext(message);
+ if (response && response.data && response.data.message) {
+ text += ' (' + response.data.message + ')'
+ }
+ toast.add('error', text);
}
},
diff --git a/moon_dashboard/moon/static/moon/model/model.controller.js b/moon_dashboard/moon/static/moon/model/model.controller.js
index d6a7503b..99a7c7ed 100644
--- a/moon_dashboard/moon/static/moon/model/model.controller.js
+++ b/moon_dashboard/moon/static/moon/model/model.controller.js
@@ -17,13 +17,13 @@
link: function (scope, element, attrs) {
element.bind('change', function (e) {
- var onFileReadFn = $parse(attrs.onReadFile);
+ var onFileRead = $parse(attrs.onReadFile);
var reader = new FileReader();
reader.onload = function () {
var fileContents = reader.result;
scope.$apply(function () {
- onFileReadFn(scope, {
+ onFileRead(scope, {
'contents': fileContents
});
});
@@ -65,8 +65,10 @@
modelService.initialize();
self.importData = function importData(text) {
+ horizon.modals.modal_spinner(gettext("Loading"))
importService.importData(JSON.parse(text)).then(function () {
modelService.initialize();
+ horizon.modals.spinner.modal('hide');
})
}
@@ -76,7 +78,8 @@
properties: {
name: { type: "string", minLength: 2, title: gettext("Name") },
description: { type: "string", minLength: 2, title: gettext("Description") }
- }
+ },
+ required: ['name', 'description']
};
var model = { name: '', description: '' };
var config = {
@@ -98,7 +101,8 @@
properties: {
name: { type: "string", minLength: 2, title: gettext("Name") },
description: { type: "string", minLength: 2, title: gettext("Description") }
- }
+ },
+ required: ['name', 'description']
};
var config = {
title: gettext('Update Model'),
@@ -118,37 +122,73 @@
modelService.removeModel(model);
}
+ self.createMetaRuleFunction = function createMetaRuleFunction(model, titleMap) {
+ return function () {
+ var schema = {
+ type: "object",
+ properties: {
+ name: { type: "string", minLength: 2, title: gettext("Name") },
+ description: { type: "string", minLength: 2, title: gettext("Description") },
+ },
+ required: ['name', 'description']
+ };
+ var metaRule = { name: '', description: '' };
+ var config = {
+ title: gettext('Create Meta Rule'),
+ schema: schema,
+ form: [
+ 'name',
+ { key: 'description', type: 'textarea' }
+ ],
+ model: metaRule
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ modelService.createMetaRule(form.model).then(function (metaRule) {
+ titleMap.push({ value: metaRule.id, name: metaRule.name })
+ model.id = metaRule.id
+ })
+ }
+ }
+ }
+
self.addMetaRule = function addMetaRule(model) {
var schema = {
type: "object",
properties: {
- name: { type: "string", minLength: 2, title: gettext("Name") },
- description: { type: "string", minLength: 2, title: gettext("Description") },
id: { type: "string", title: gettext("Select a Meta Rule:") }
- }
+ },
+ required: ['id']
};
- var metaRule = { name: '', description: '' };
var titleMap = util.arrayToTitleMap(modelService.metaRules)
+ var formModel = { id: null }
var config = {
title: gettext('Add Meta Rule'),
schema: schema,
- form: [{ key: 'id', type: 'select', titleMap: titleMap }, { type: 'help', helpvalue: gettext("Or create a new one:") }, 'name', { key: 'description', type: 'textarea' }],
- model: metaRule
+ form: [
+ { key: 'id', type: 'select', titleMap: titleMap },
+ {
+ key: 'createButton',
+ type: 'button',
+ title: gettext('Create Meta Rule'),
+ icon: 'fa fa-plus',
+ onClick: self.createMetaRuleFunction(formModel, titleMap)
+ }
+ ],
+ model: formModel
};
+ if (modelService.metaRules.length == 1) {
+ formModel.id = modelService.metaRules[0].id
+ }
+
ModalFormService.open(config).then(submit);
function submit(form) {
- function addMetaRuleToModel(metaRule) {
- var modelCopy = angular.copy(model);
- modelCopy.meta_rules.push(metaRule);
- modelService.updateModel(modelCopy);
- }
-
- if (form.model.name) {
- modelService.createMetaRule(form.model).then(addMetaRuleToModel)
- } else if (form.model.id) {
- addMetaRuleToModel(modelService.getMetaRule(form.model.id));
- }
+ var metaRule = modelService.getMetaRule(form.model.id);
+ var modelCopy = angular.copy(model);
+ modelCopy.meta_rules.push(metaRule);
+ modelService.updateModel(modelCopy);
}
}
@@ -158,7 +198,8 @@
properties: {
name: { type: "string", minLength: 2, title: gettext("Name") },
description: { type: "string", minLength: 2, title: gettext("Description") }
- }
+ },
+ required: ['name', 'description']
};
var metaRuleCopy = angular.copy(metaRule);
var config = {
@@ -188,38 +229,69 @@
}
}
+ self.createCategoryFunction = function createCategoryFunction(type, formModel, titleMap) {
+ return function () {
+ var schema = {
+ type: "object",
+ properties: {
+ name: { type: "string", minLength: 2, title: gettext("Name") },
+ description: { type: "string", minLength: 2, title: gettext("Description") },
+ },
+ required: ['name', 'description']
+ };
+ var metaRule = { name: '', description: '' };
+ var config = {
+ title: gettext('Create Category'),
+ schema: schema,
+ form: [
+ 'name',
+ { key: 'description', type: 'textarea' }
+ ],
+ model: metaRule
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ modelService.createCategory(type, form.model).then(function (category) {
+ titleMap.push({ value: category.id, name: category.name })
+ formModel.id = category.id
+ })
+ }
+ }
+ }
+
self.addCategory = function addCategory(type, metaRule) {
var typeValue = categoryMap[type];
var schema = {
type: "object",
properties: {
- name: { type: "string", minLength: 2, title: gettext("Name") },
- description: { type: "string", minLength: 2, title: gettext("Description") },
id: { type: "string", title: gettext("Select a Category:") }
- }
+ },
+ required: ['id']
};
- var category = { name: '', description: '' };
var titleMap = util.arrayToTitleMap(modelService[typeValue.serviceListName])
+ var formModel = { id: null }
var config = {
title: gettext(typeValue.addTitle),
schema: schema,
- form: [{ key: 'id', type: 'select', titleMap: titleMap }, { type: 'help', helpvalue: gettext("Or create a new one:") }, 'name', { key: 'description', type: 'textarea' }],
- model: category
+ form: [
+ { key: 'id', type: 'select', titleMap: titleMap },
+ {
+ key: 'createButton',
+ type: 'button',
+ title: gettext('Create Category'),
+ icon: 'fa fa-plus',
+ onClick: self.createCategoryFunction(type, formModel, titleMap)
+ }],
+ model: formModel
};
ModalFormService.open(config).then(submit);
function submit(form) {
- function addCategoryToMetaRule(category) {
- var metaRuleCopy = angular.copy(metaRule);
- metaRuleCopy[typeValue.listName].push(category);
- modelService.updateMetaRule(metaRuleCopy)
- }
-
- if (form.model.name) {
- modelService.createCategory(type, form.model).then(addCategoryToMetaRule)
- } else if (form.model.id) {
- addCategoryToMetaRule(modelService.getCategory(type, form.model.id));
- }
+ var category = modelService.getCategory(type, form.model.id);
+ var metaRuleCopy = angular.copy(metaRule);
+ metaRuleCopy[typeValue.listName].push(category);
+ modelService.updateMetaRule(metaRuleCopy)
}
}
diff --git a/moon_dashboard/moon/static/moon/model/model.html b/moon_dashboard/moon/static/moon/model/model.html
index 98d64c75..97f08910 100644
--- a/moon_dashboard/moon/static/moon/model/model.html
+++ b/moon_dashboard/moon/static/moon/model/model.html
@@ -62,10 +62,6 @@
<translate>Import</translate>
</label>
<input id="file" class="input-file" type="file" on-read-file="ctrl.importData(contents)" accept="application/json,.json"/>
- <!--button type="button" class="btn btn-primary" ng-click="ctrl.createModel()">
- <span class="fa fa-upload"></span>
- <translate>Import</translate>
- </button-->
</div>
</div>
@@ -115,19 +111,19 @@
<tr>
<td>
<p ng-repeat="category in metaRule.subject_categories">
- <span>{$ category.name $}</span>
+ <span title="{$ category.description $}">{$ category.name $}</span>
<button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeCategoryFromMetaRule('subject', metaRule, category)" title="{$ 'Remove Subject' | translate $}"></button>
</p>
</td>
<td>
<p ng-repeat="category in metaRule.object_categories">
- <span>{$ category.name $}</span>
+ <span title="{$ category.description $}">{$ category.name $}</span>
<button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeCategoryFromMetaRule('object', metaRule, category)" title="{$ 'Remove Object' | translate $}"></button>
</p>
</td>
<td>
<p ng-repeat="category in metaRule.action_categories">
- <span>{$ category.name $}</span>
+ <span title="{$ category.description $}">{$ category.name $}</span>
<button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeCategoryFromMetaRule('action', metaRule, category)" title="{$ 'Remove Action' | translate $}"></button>
</p>
</td>
diff --git a/moon_dashboard/moon/static/moon/model/model.service.js b/moon_dashboard/moon/static/moon/model/model.service.js
index 76c3da01..986eb6b1 100755
--- a/moon_dashboard/moon/static/moon/model/model.service.js
+++ b/moon_dashboard/moon/static/moon/model/model.service.js
@@ -205,6 +205,7 @@
return modelsMap[id];
},
createModel: function createModel(model) {
+ model.meta_rules = [];
modelResource.create(null, model, success, util.displayErrorFunction('Unable to create model'));
function success(data) {
@@ -235,6 +236,10 @@
return metaRulesMap[id];
},
createMetaRule: function createMetaRule(metaRule) {
+ metaRule.subject_categories = [];
+ metaRule.object_categories = [];
+ metaRule.action_categories = [];
+
return metaRuleResource.create(null, metaRule).$promise.then(function (data) {
util.displaySuccess('Meta Rule created');
return createMetaRuleInternal(data.meta_rules)[0];
diff --git a/moon_dashboard/moon/static/moon/pdp/pdp.controller.js b/moon_dashboard/moon/static/moon/pdp/pdp.controller.js
index c57f3b28..1859b1f8 100644
--- a/moon_dashboard/moon/static/moon/pdp/pdp.controller.js
+++ b/moon_dashboard/moon/static/moon/pdp/pdp.controller.js
@@ -19,7 +19,8 @@
properties: {
name: { type: "string", minLength: 2, title: gettext("Name") },
description: { type: "string", minLength: 2, title: gettext("Description") }
- }
+ },
+ required: ['name', 'description']
};
var pdp = { name: '', description: '' };
var config = {
@@ -41,7 +42,8 @@
properties: {
name: { type: "string", minLength: 2, title: gettext("Name") },
description: { type: "string", minLength: 2, title: gettext("Description") }
- }
+ },
+ required: ['name', 'description']
};
var config = {
title: gettext('Update PDP'),
@@ -66,7 +68,8 @@
type: "object",
properties: {
id: { type: "string", title: gettext("Select a Policy:") }
- }
+ },
+ required: ['id']
};
var titleMap = util.arrayToTitleMap(pdpService.policies)
var config = {
@@ -97,7 +100,8 @@
type: "object",
properties: {
id: { type: "string", title: gettext("Select a Project:") }
- }
+ },
+ required: ['id']
};
var model = {id : pdp.keystone_project_id};
diff --git a/moon_dashboard/moon/static/moon/policy/policy.controller.js b/moon_dashboard/moon/static/moon/policy/policy.controller.js
index 6c6631cf..a3cc18f1 100644
--- a/moon_dashboard/moon/static/moon/policy/policy.controller.js
+++ b/moon_dashboard/moon/static/moon/policy/policy.controller.js
@@ -32,21 +32,23 @@
function createAddDataButton(type, index, category, config, policy) {
config.form.push({
- "key": type + index + "Button",
- "type": "button",
- "title": "Add",
- onClick: createDataFunction(type, category, policy)
+ key: type + index + "Button",
+ type: "button",
+ title: gettext("Create Data"),
+ icon: 'fa fa-plus',
+ onClick: createDataFunction(type, category, policy, config.model, type+index)
})
}
- function createDataFunction(type, category, policy) {
+ function createDataFunction(type, category, policy, formModel, key) {
return function () {
var schema = {
type: "object",
properties: {
name: { type: "string", minLength: 2, title: gettext("Name") },
description: { type: "string", minLength: 2, title: gettext("Description") },
- }
+ },
+ required: ['name', 'description']
};
var data = { name: '', description: '' };
var config = {
@@ -61,6 +63,7 @@
policyService.createData(type, policy, category, form.model).then(
function (data) {
util.pushAll(dataTitleMaps[category.id], util.arrayToTitleMap(data));
+ formModel[key] = data[0].id
}
);
}
@@ -82,6 +85,7 @@
var titleMap = getOrCreateDataTitleMap(category, data, policy);
config.schema.properties[type + i] = { type: "string", title: gettext('Select ' + type + ' data of ' + category.name + ' category') };
config.form.push({ key: type + i, type: 'select', titleMap: titleMap });
+ config.schema.required.push(type + i);
createAddDataButton(type, i, category, config, policy);
}
}
@@ -102,7 +106,8 @@
description: { type: "string", minLength: 2, title: gettext("Description") },
genre: { type: "string", title: gettext("genre") },
model_id: { type: "string", title: gettext("Select a Model:") }
- }
+ },
+ required: ['name', 'description', 'genre', 'model_id']
};
var policy = { name: '', description: '', model_id: null, genre: '' };
var titleMap = util.arrayToTitleMap(modelService.models)
@@ -126,7 +131,8 @@
name: { type: "string", minLength: 2, title: gettext("Name") },
description: { type: "string", minLength: 2, title: gettext("Description") },
genre: { type: "string", title: gettext("Genre") },
- }
+ },
+ required: ['name', 'description', 'genre']
};
var config = {
title: gettext('Update Policy'),
@@ -146,7 +152,8 @@
type: "object",
properties: {
instructions: { type: "string", title: gettext("Instructions") }
- }
+ },
+ required: ['instructions']
};
var config = {
@@ -179,11 +186,16 @@
}
self.addRule = function addRule(policy) {
+ if (policy.model.meta_rules.length == 1) {
+ self.addRuleWithMetaRule(policy, policy.model.meta_rules[0]);
+ return;
+ }
var schema = {
type: "object",
properties: {
metaRuleId: { type: "string", title: gettext("Select a Metarule:") }
- }
+ },
+ required: ['metaRuleId']
};
var rule = { metaRuleId: null };
var titleMap = util.arrayToTitleMap(policy.model.meta_rules);
@@ -201,7 +213,7 @@
}
self.removePolicy = function removePolicy(policy) {
- if (confirm(gettext('Are you sure to delete this Policy?')))
+ if (confirm(gettext('Are you sure to delete this Policy? (Associated perimeter, data an PDP will be deleted too)')))
policyService.removePolicy(policy);
}
@@ -216,6 +228,7 @@
self.showRule = function showRule(rule) {
self.selectedRule = rule;
+ self.currentData = null;
}
self.hideRule = function hideRule() {
@@ -229,14 +242,22 @@
type: type,
loading: true,
perimeters: [],
- assignments: []
+ allPerimeters: [],
+ assignments: [],
}
policyService.loadPerimetersAndAssignments(type, policy).then(function (values) {
var category = categoryMap[type];
self.currentData.loading = false;
self.currentData.perimeters = values.perimeters;
- for (var index = 0; index < values.assignments.length; index++) {
+ var index;
+ for (index = 0; index < values.allPerimeters.length; index++) {
+ var perimeter = values.allPerimeters[index];
+ if (perimeter.policy_list.indexOf(policy.id) < 0) {
+ self.currentData.allPerimeters.push(perimeter);
+ }
+ }
+ for (index = 0; index < values.assignments.length; index++) {
var assignment = values.assignments[index];
if (assignment.assignments.indexOf(data.id) >= 0) {
var perimeter = values.perimetersMap[assignment[category.perimeterId]];
@@ -253,10 +274,12 @@
properties: {
name: { type: "string", minLength: 2, title: gettext("Name") },
description: { type: "string", minLength: 2, title: gettext("Description") },
- }
+ },
+ required: ['name', 'description']
};
if (type == 'subject') {
schema.properties.email = { type: "email", "type": "string", "pattern": "^\\S+@\\S+$", title: gettext("Email") }
+ schema.required.push('email');
}
var perimeter = { name: '', description: '' };
var config = {
@@ -268,7 +291,7 @@
if (type == 'subject') {
config.form.push('email');
}
-
+
ModalFormService.open(config).then(submit);
function submit(form) {
@@ -278,6 +301,13 @@
}
}
+ self.addPerimeter = function addPerimeter(type, policy, perimeter) {
+ policyService.addPerimeterToPolicy(type, policy, perimeter).then(function () {
+ self.currentData.allPerimeters.splice(self.currentData.allPerimeters.indexOf(perimeter), 1);
+ self.currentData.perimeters.push(perimeter);
+ })
+ }
+
self.assign = function assign(type, policy, perimeter, data) {
policyService.createAssignment(type, policy, perimeter, data).then(function () {
self.currentData.assignments.push(perimeter);
@@ -291,5 +321,21 @@
self.currentData.assignments.splice(self.currentData.assignments.indexOf(perimeter), 1);
})
}
+
+ self.removePerimeterFromPolicy = function removePerimeterFromPolicy(type, policy, perimeter) {
+ if (confirm(gettext('Are you sure to delete this Perimeter? (Associated assignments will be deleted too)')))
+ policyService.removePerimeterFromPolicy(type, policy, perimeter).then(function () {
+ self.currentData.perimeters.splice(self.currentData.perimeters.indexOf(perimeter), 1);
+ perimeter.policy_list.splice(perimeter.policy_list.indexOf(policy.id), 1);
+ if (perimeter.policy_list.length > 0) {
+ self.currentData.allPerimeters.push(perimeter);
+ }
+ })
+ }
+
+ self.removeData = function removeData(type, policy, data) {
+ if (confirm(gettext('Are you sure to delete this Data? (Associated assignments and rules will be deleted too)')))
+ policyService.removeData(type, policy, data)
+ }
}
})(); \ No newline at end of file
diff --git a/moon_dashboard/moon/static/moon/policy/policy.html b/moon_dashboard/moon/static/moon/policy/policy.html
index 70789fbb..ba13bec2 100644
--- a/moon_dashboard/moon/static/moon/policy/policy.html
+++ b/moon_dashboard/moon/static/moon/policy/policy.html
@@ -10,7 +10,7 @@
</div>
<div class="list-group">
- <div ng-repeat="policy in ctrl.model.policies | orderBy:'name' | filter:filterText" class="list-group-item">
+ <div ng-repeat="policy in ctrl.model.policies | orderBy:'name' | filter:filterText" class="list-group-item" ng-init="toggle = {};toggle.showUnused = false">
<h3 class="list-group-item-heading inline">{$ policy.name $}</h3>
<div class="pull-right">
<button type="button" class="fa fa-trash" title="{$ 'Remove Policy' | translate $}" ng-click="ctrl.removePolicy(policy)"></button>
@@ -24,6 +24,46 @@
<translate>Genre:</translate>
<translate>{$ policy.genre ? policy.genre : 'none' $}</translate>
</h4>
+ <div ng-if="policy.unusedSubjectData.length
+ || policy.unusedSubjectData.length
+ || policy.unusedSubjectData.length" class="alert alert-dismissable alert-warning">
+ <button type="button" class="close" data-dismiss="alert" ng-click="toggle.showUnused=false">×</button>
+ <h4 translate>Warning!</h4>
+ <p translate>
+ Some data are unused, please check them and delete them if necessary.
+ <a href="" ng-click="toggle.showUnused=true" ng-show="!toggle.showUnused" translate>Show unused data</a>
+ <a href="" ng-click="toggle.showUnused=false" ng-show="toggle.showUnused" translate>Hide unused data</a>
+ </p>
+ </div>
+
+ <div ng-if="toggle.showUnused" class="list-group-item-text overflow-hidden">
+ <div class="list-group col-lg-3" ng-if="policy.unusedSubjectData.length">
+ <h3 class="list-group-item active" translate>Unused Subject data</h3>
+ <div ng-repeat="subject in policy.unusedSubjectData | orderBy:'name'" class="list-group-item">
+ <h4 class="list-group-item-heading inline" title="{$ subject.description $}">{$ subject.name $}</h4>
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeData('subject', policy, subject)" title="{$ 'Remove Subject data' | translate $}"></button>
+ </div>
+ </div>
+
+ <div class="list-group col-lg-3" ng-if="policy.unusedObjectData.length">
+ <h3 class="list-group-item active" translate>Unused Object data</h3>
+ <div ng-repeat="object in policy.unusedObjectData | orderBy:'name'" class="list-group-item">
+ <h4 class="list-group-item-heading inline" title="{$ object.description $}">{$ object.name $}</h4>
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeData('object', policy, object)" title="{$ 'Remove Object data' | translate $}"></button>
+ </div>
+ </div>
+
+ <div class="list-group col-lg-3" ng-if="policy.unusedActionData.length">
+ <h3 class="list-group-item active" translate>Unused Action data</h3>
+ <div ng-repeat="action in policy.unusedActionData | orderBy:'name'" class="list-group-item">
+ <h4 class="list-group-item-heading inline" title="{$ action.description $}">{$ action.name $}</h4>
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeData('action', policy, action)" title="{$ 'Remove Action data' | translate $}"></button>
+ </div>
+ </div>
+
+ </div>
+
+
<details class="list-group-item-text">
<summary ng-click="ctrl.populatePolicy(policy)">
<h4 class="inline" translate>Rules</h4>
@@ -85,7 +125,7 @@
<tr>
<td>
<p ng-repeat="data in rule.subjectData">
- <span ng-class="{'text-primary': ctrl.currentData.data == data}">{$ data.name $}</span>
+ <span ng-class="{'text-primary': ctrl.currentData.data == data}" title="{$ data.description $}">{$ data.name $}</span>
<button ng-if="ctrl.currentData.data != data" type="button" class="fa fa-exchange pull-right" ng-click="ctrl.assignData('subject', policy, data)"
title="{$ 'Assign to perimeters' | translate $}"></button>
<button ng-if="ctrl.currentData.data == data" type="button" class="fa fa-times pull-right" ng-click="ctrl.currentData = null"
@@ -94,7 +134,7 @@
</td>
<td>
<p ng-repeat="data in rule.objectData">
- <span ng-class="{'text-primary': ctrl.currentData.data == data}">{$ data.name $}</span>
+ <span ng-class="{'text-primary': ctrl.currentData.data == data}" title="{$ data.description $}">{$ data.name $}</span>
<button ng-if="ctrl.currentData.data != data" type="button" class="fa fa-exchange pull-right" ng-click="ctrl.assignData('object', policy, data)"
title="{$ 'Assign to perimeters' | translate $}"></button>
<button ng-if="ctrl.currentData.data == data" type="button" class="fa fa-times pull-right" ng-click="ctrl.currentData = null"
@@ -103,7 +143,7 @@
</td>
<td>
<p ng-repeat="data in rule.actionData">
- <span ng-class="{'text-primary': ctrl.currentData.data == data}">{$ data.name $}</span>
+ <span ng-class="{'text-primary': ctrl.currentData.data == data}" title="{$ data.description $}">{$ data.name $}</span>
<button ng-if="ctrl.currentData.data != data" type="button" class="fa fa-exchange pull-right" ng-click="ctrl.assignData('action', policy, data)"
title="{$ 'Assign to perimeters' | translate $}"></button>
<button ng-if="ctrl.currentData.data == data" type="button" class="fa fa-times pull-right" ng-click="ctrl.currentData = null"
@@ -131,18 +171,34 @@
</div>
<div>
<div class="col-lg-4">
- <h4 translate>Available perimeters</h4>
+ <h4 translate>All perimeters</h4>
+ <div class="w-100 height-200 scroll list-group border">
+ <button class="list-group-item" ng-repeat="perimeter in ctrl.currentData.allPerimeters | orderBy:'name' | filter:filterPerimeter"
+ title="{$ perimeter.description $}" ng-click="ctrl.addPerimeter(ctrl.currentData.type, policy, perimeter)">{$ perimeter.name $}</button>
+
+ </div>
+ <p translate class="mt-5">Click to add</p>
+ </div>
+
+ <div class="col-lg-4">
+ <h4 translate>Policy perimeters</h4>
<div class="w-100 height-200 scroll list-group border">
- <button class="list-group-item" ng-repeat="perimeter in ctrl.currentData.perimeters | orderBy:'name' | filter:filterPerimeter" title="{$ perimeter.description $}"
- ng-click="ctrl.assign(ctrl.currentData.type, policy, perimeter, ctrl.currentData.data)">{$ perimeter.name $}</button>
+ <div ng-click="ctrl.assign(ctrl.currentData.type, policy, perimeter, ctrl.currentData.data)" class="list-group-item" ng-repeat="perimeter in ctrl.currentData.perimeters | orderBy:'name' | filter:filterPerimeter">
+ <span title="{$ perimeter.description $}">
+ {$ perimeter.name $}
+ </span>
+ <button type="button" class="fa fa-trash pull-right" ng-click="$event.stopPropagation();ctrl.removePerimeterFromPolicy(ctrl.currentData.type, policy, perimeter)"
+ title="{$ 'Remove Perimeter' | translate $}"></button>
+ </div>
+
</div>
<p translate class="mt-5">Click to assign</p>
</div>
<div class="col-lg-4">
<h4 translate>Assigned perimeters</h4>
<div class="w-100 list-group border height-200 scroll">
- <button class="list-group-item" ng-repeat="perimeter in ctrl.currentData.assignments | orderBy:'name' | filter:filterPerimeter" title="{$ perimeter.description $}"
- ng-click="ctrl.unassign(ctrl.currentData.type, policy, perimeter, ctrl.currentData.data)">{$ perimeter.name $}</button>
+ <button class="list-group-item" ng-repeat="perimeter in ctrl.currentData.assignments | orderBy:'name' | filter:filterPerimeter"
+ title="{$ perimeter.description $}" ng-click="ctrl.unassign(ctrl.currentData.type, policy, perimeter, ctrl.currentData.data)">{$ perimeter.name $}</button>
</div>
<p translate class="mt-5">Click to unassign</p>
</div>
diff --git a/moon_dashboard/moon/static/moon/policy/policy.service.js b/moon_dashboard/moon/static/moon/policy/policy.service.js
index 87250b2e..3781156d 100755
--- a/moon_dashboard/moon/static/moon/policy/policy.service.js
+++ b/moon_dashboard/moon/static/moon/policy/policy.service.js
@@ -26,34 +26,55 @@
remove: { method: 'DELETE' }
});
- var policySubjectDataResource = $resource(host + '/policies/' + ':policy_id' + '/subject_data/' + ':category_id', {}, {
+ var policySubjectDataResource = $resource(host + '/policies/' + ':policy_id' + '/subject_data/' + ':category_id' + '/' + ':data_id', {}, {
query: {method: 'GET'},
create: { method: 'POST' },
+ remove: { method: 'DELETE' }
})
- var policyObjectDataResource = $resource(host + '/policies/' + ':policy_id' + '/object_data/' + ':category_id', {}, {
+ var policyObjectDataResource = $resource(host + '/policies/' + ':policy_id' + '/object_data/' + ':category_id' + '/' + ':data_id', {}, {
query: {method: 'GET'},
create: { method: 'POST' },
+ remove: { method: 'DELETE' }
})
- var policyActionDataResource = $resource(host + '/policies/' + ':policy_id' + '/action_data/' + ':category_id', {}, {
+ var policyActionDataResource = $resource(host + '/policies/' + ':policy_id' + '/action_data/' + ':category_id' + '/' + ':data_id', {}, {
query: {method: 'GET'},
create: { method: 'POST' },
+ remove: { method: 'DELETE' }
})
- var policySubjectPerimetersResource = $resource(host + '/policies/' + ':policy_id' + '/subjects', {}, {
+ var policySubjectPerimetersResource = $resource(host + '/policies/' + ':policy_id' + '/subjects/' + ':perimeter_id', {}, {
query: {method: 'GET'},
create: { method: 'POST' },
+ remove: { method: 'DELETE' }
})
- var policyObjectPerimetersResource = $resource(host + '/policies/' + ':policy_id' + '/objects', {}, {
+ var policyObjectPerimetersResource = $resource(host + '/policies/' + ':policy_id' + '/objects/' + ':perimeter_id', {}, {
query: {method: 'GET'},
create: { method: 'POST' },
+ remove: { method: 'DELETE' }
})
- var policyActionPerimetersResource = $resource(host + '/policies/' + ':policy_id' + '/actions', {}, {
+ var policyActionPerimetersResource = $resource(host + '/policies/' + ':policy_id' + '/actions/' + ':perimeter_id', {}, {
query: {method: 'GET'},
create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ })
+
+ var subjectPerimetersResource = $resource(host + '/subjects/' + ':perimeter_id', {}, {
+ query: {method: 'GET'},
+ update: { method: 'PATCH' }
+ })
+
+ var objectPerimetersResource = $resource(host + '/objects/' + ':perimeter_id', {}, {
+ query: {method: 'GET'},
+ update: { method: 'PATCH' }
+ })
+
+ var actionPerimetersResource = $resource(host + '/actions/' + ':perimeter_id', {}, {
+ query: {method: 'GET'},
+ update: { method: 'PATCH' }
})
var policySubjectAssignmentsResource = $resource(host + '/policies/' + ':policy_id' + '/subject_assignments/' + ':perimeter_id' + '/' + ':category_id' + '/' + ':data_id', {}, {
@@ -81,30 +102,36 @@
arrayName: "subjectData",
mapName: "subjectDataMap",
responseName: "subject_data",
- perimeterResource: policySubjectPerimetersResource,
+ policyPerimeterResource: policySubjectPerimetersResource,
+ perimeterResource: subjectPerimetersResource,
assignmentResource: policySubjectAssignmentsResource,
perimeterResponseName: "subjects",
assignmentResponseName: "subject_assignments",
+ unusedArrayName: "unusedSubjectData",
},
'object': {
resource: policyObjectDataResource,
arrayName: "objectData",
mapName: "objectDataMap",
responseName: "object_data",
- perimeterResource: policyObjectPerimetersResource,
+ policyPerimeterResource: policyObjectPerimetersResource,
+ perimeterResource: objectPerimetersResource,
assignmentResource: policyObjectAssignmentsResource,
perimeterResponseName: "objects",
assignmentResponseName: "object_assignments",
+ unusedArrayName: "unusedObjectData",
},
'action': {
resource: policyActionDataResource,
arrayName: "actionData",
mapName: "actionDataMap",
responseName: "action_data",
- perimeterResource: policyActionPerimetersResource,
+ policyPerimeterResource: policyActionPerimetersResource,
+ perimeterResource: actionPerimetersResource,
assignmentResource: policyActionAssignmentsResource,
perimeterResponseName: "actions",
assignmentResponseName: "action_assignments",
+ unusedArrayName: "unusedActionData",
}
}
@@ -149,6 +176,7 @@
function removeRuleInternal(policy, rule) {
policy.rules.splice(policy.rules.indexOf(rule), 1);
+ updateUnusedData(policy);
}
function loadPolicyRule(policy) {
@@ -161,11 +189,40 @@
}
$q.all(queries).then(function (result) {
- createRules(policy, result.rules, result.subjectData, result.objectData, result.actionData)
+ createRules(policy, result.rules, result.subjectData, result.objectData, result.actionData);
+ updateUnusedData(policy);
}, util.displayErrorFunction('Unable to load rules'))
}
}
+ function updateUnusedData(policy) {
+ policy.unusedSubjectData.splice(0, policy.unusedSubjectData.length);
+ util.pushAll(policy.unusedSubjectData, policy.subjectData);
+
+ policy.unusedObjectData.splice(0, policy.unusedObjectData.length);
+ util.pushAll(policy.unusedObjectData, policy.objectData);
+
+ policy.unusedActionData.splice(0, policy.unusedActionData.length);
+ util.pushAll(policy.unusedActionData, policy.actionData);
+
+ for (var i = 0; i < policy.rules.length; i++) {
+ var rule = policy.rules[i];
+ removeUsedData(rule.subjectData, policy.unusedSubjectData);
+ removeUsedData(rule.objectData, policy.unusedObjectData);
+ removeUsedData(rule.actionData, policy.unusedActionData);
+ }
+ }
+
+ function removeUsedData(list, orphanList) {
+ for (var j = 0; j < list.length; j++) {
+ var data = list[j];
+ var notOrphanIndex = util.indexOf(orphanList, "id", data.id);
+ if (notOrphanIndex >= 0) {
+ orphanList.splice(notOrphanIndex, 1);
+ }
+ }
+ }
+
function createRules(policy, rulesData, subjectsData, objectsData, actionsData) {
policy.rules = rulesData ? rulesData.rules.rules : [];
policy.subjectDataMap = subjectsData.subject_data.length > 0 ? subjectsData.subject_data[0].data : [];
@@ -174,6 +231,9 @@
policy.objectData = util.mapToArray(policy.objectDataMap);
policy.actionDataMap = actionsData.action_data.length > 0 ? actionsData.action_data[0].data : [];
policy.actionData = util.mapToArray(policy.actionDataMap);
+ policy.unusedSubjectData = [];
+ policy.unusedObjectData = [];
+ policy.unusedActionData = [];
for (var i = 0; i < policy.rules.length; i++) {
var rule = policy.rules[i];
populateRule(policy, rule);
@@ -251,6 +311,7 @@
policy.rules.push(populateRule(policy, rule))
}
util.displaySuccess('Rule created');
+ updateUnusedData(policy);
}
},
removeRuleFromPolicy: function removeRuleFromPolicy(policy, rule) {
@@ -267,14 +328,27 @@
function (data) {
var result = util.createInternal(data[categoryValue.responseName].data, policy[categoryValue.arrayName], policy[categoryValue.mapName]);
util.displaySuccess('Data created');
+ util.pushAll(policy[categoryValue.unusedArrayName], result);
return result;
},
util.displayErrorFunction('Unable to create Data')
);
},
+ removeData: function removeData(type, policy, data) {
+ var categoryValue = categoryMap[type];
+ return categoryValue.resource.remove({ policy_id: policy.id, category_id: data.category_id, data_id: data.id }).$promise.then(
+ function (data) {
+ policy[categoryValue.arrayName].splice(policy.subjectData.indexOf(data), 1);
+ policy[categoryValue.unusedArrayName].splice(policy.unusedSubjectData.indexOf(data), 1);
+ delete policy[categoryValue.mapName][data.id];
+ util.displaySuccess('Data removed');
+ },
+ util.displayErrorFunction('Unable to remove Data')
+ );
+ },
createPerimeter: function createPerimeter(type, policy, perimeter) {
var categoryValue = categoryMap[type];
- return categoryValue.perimeterResource.create({ policy_id: policy.id }, perimeter).$promise.then(
+ return categoryValue.policyPerimeterResource.create({ policy_id: policy.id }, perimeter).$promise.then(
function (data) {
util.displaySuccess('Perimeter created');
return util.mapToArray(data[categoryValue.perimeterResponseName]);
@@ -282,10 +356,33 @@
util.displayErrorFunction('Unable to create Perimeter')
);
},
+ removePerimeterFromPolicy: function removePerimeterFromPolicy(type, policy, perimeter) {
+ var categoryValue = categoryMap[type];
+
+ return categoryValue.policyPerimeterResource.remove({ policy_id: policy.id, perimeter_id: perimeter.id }, null).$promise.then(
+ function (data) {
+ util.displaySuccess('Perimeter removed');
+ return perimeter;
+ },
+ util.displayErrorFunction('Unable to remove Perimeter')
+ )
+ },
+ addPerimeterToPolicy: function addPerimeterToPolicy(type, policy, perimeter) {
+ var categoryValue = categoryMap[type];
+ perimeter.policy_list.push(policy.id);
+
+ return categoryValue.perimeterResource.update({ perimeter_id: perimeter.id }, perimeter).$promise.then(
+ function (data) {
+ util.displaySuccess('Perimeter added');
+ },
+ util.displayErrorFunction('Unable to add Perimeter')
+ )
+ },
loadPerimetersAndAssignments: function loadPerimetersAndAssignments(type, policy) {
var categoryValue = categoryMap[type];
var queries = {
- perimeters: categoryValue.perimeterResource.query({ policy_id: policy.id }).$promise,
+ allPerimeters: categoryValue.perimeterResource.query().$promise,
+ perimeters: categoryValue.policyPerimeterResource.query({ policy_id: policy.id }).$promise,
assignments: categoryValue.assignmentResource.query({ policy_id: policy.id }).$promise,
}
@@ -294,6 +391,7 @@
result.assignments = util.mapToArray(data.assignments[categoryValue.assignmentResponseName]);
result.perimetersMap = data.perimeters[categoryValue.perimeterResponseName];
result.perimeters = util.mapToArray(result.perimetersMap);
+ result.allPerimeters = util.mapToArray(data.allPerimeters[categoryValue.perimeterResponseName]);
return result;
}, util.displayErrorFunction('Unable to load Perimeters'))
diff --git a/moon_dashboard/moon/static/moon/policy/policy.service.spec.js b/moon_dashboard/moon/static/moon/policy/policy.service.spec.js
index 045bf9b3..8d0ca8bf 100755
--- a/moon_dashboard/moon/static/moon/policy/policy.service.spec.js
+++ b/moon_dashboard/moon/static/moon/policy/policy.service.spec.js
@@ -329,6 +329,157 @@
});
+ it('should create perimeter', function () {
+ var perimeterCreatedData = {
+ subjects: {
+ 'subjectId1': { name: 'subject1', description: 'sDescription1' },
+ }
+ };
+
+ $httpBackend.expectPOST(URI.API + '/policies/policyId1/subjects').respond(200, perimeterCreatedData);
+ var type = 'subject';
+ var policy = { id: 'policyId1' };
+ var perimeter = { name: 'subject1', description: 'sDescription1' };
+
+ var promise = service.createPerimeter(type, policy, perimeter);
+ $httpBackend.flush();
+
+ promise.then(function (result) {
+ expect(result.length).toBe(1);
+ var perimeter = result[0];
+ expect(perimeter.id).toBe('subjectId1');
+ expect(perimeter.name).toBe('subject1');
+ expect(perimeter.description).toBe('sDescription1');
+ })
+ });
+
+ it('should remove perimeter', function () {
+ $httpBackend.expectDELETE(URI.API + '/policies/policyId1/subjects/subjectId1').respond(200);
+ var type = 'subject';
+ var policy = { id: 'policyId1' };
+ var perimeter = { id: 'subjectId1' };
+
+ var promise = service.removePerimeterFromPolicy(type, policy, perimeter);
+ $httpBackend.flush();
+
+ promise.then(function (result) {
+ expect(result.id).toBe('subjectId1');
+ })
+ });
+
+ it('should load perimeters and assignments', function () {
+ var assignmentsData = {
+ subject_assignments: {
+ 'subjectAssignmentId1': {
+ id: 'subjectAssignmentId1',
+ policy_id: 'policyId1',
+ subject_id: 'subjectId1',
+ category_id: 'subjectCategoryId1',
+ assignments: ['subjectDataId1']
+ },
+ }
+ };
+
+ var perimetersData = {
+ subjects: {
+ 'subjectId1': { name: 'subject1', description: 'sDescription1' },
+ }
+ };
+
+ var allPerimetersData = {
+ subjects: {
+ 'subjectId1': { name: 'subject1', description: 'sDescription1' },
+ 'subjectId2': { name: 'subject2', description: 'sDescription2' },
+ }
+ };
+
+ var type = 'subject';
+ var policy = { id: 'policyId1' };
+ $httpBackend.expectGET(URI.API + '/subjects').respond(200, allPerimetersData);
+ $httpBackend.expectGET(URI.API + '/policies/policyId1/subjects').respond(200, perimetersData);
+ $httpBackend.expectGET(URI.API + '/policies/policyId1/subject_assignments').respond(200, assignmentsData);
+
+ var promise = service.loadPerimetersAndAssignments(type, policy);
+
+ $httpBackend.flush();
+
+ promise.then(function (result) {
+ expect(result.perimeters.length).toBe(1);
+ var perimeter = result.perimeters[0];
+ expect(perimeter.id).toBe('subjectId1');
+ expect(perimeter.name).toBe('subject1');
+ expect(perimeter.description).toBe('sDescription1');
+
+ expect(result.allPerimeters.length).toBe(2);
+ perimeter = result.allPerimeters[0];
+ expect(perimeter.id).toBe('subjectId1');
+ expect(perimeter.name).toBe('subject1');
+ expect(perimeter.description).toBe('sDescription1');
+
+ perimeter = result.allPerimeters[1];
+ expect(perimeter.id).toBe('subjectId2');
+ expect(perimeter.name).toBe('subject2');
+ expect(perimeter.description).toBe('sDescription2');
+
+
+ expect(result.assignments.length).toBe(1);
+ var assignment = result.assignments[0];
+ expect(assignment.id).toBe('subjectAssignmentId1');
+ expect(assignment.policy_id).toBe('policyId1');
+ expect(assignment.subject_id).toBe('subjectId1');
+ expect(assignment.category_id).toBe('subjectCategoryId1');
+ expect(assignment.assignments.length).toBe(1);
+ expect(assignment.assignments[0]).toBe('subjectDataId1');
+ })
+
+ });
+
+ it('should create assignment', function () {
+ var assignmentCreatedData = {
+ subject_assignments: {
+ 'subjectAssignmentId1': {
+ id: 'subjectAssignmentId1',
+ policy_id: 'policyId1',
+ subject_id: 'subjectId1',
+ category_id: 'subjectCategoryId1',
+ assignments: ['subjectDataId1']
+ },
+ }
+ };
+
+ var type = 'subject';
+ var policy = { id: 'policyId1' };
+ var perimeter = { id: 'subjectId1' };
+ var data = { id: 'subjectDataId1', category_id: 'subjectCategoryId1'};
+
+ $httpBackend.expectPOST(URI.API + '/policies/policyId1/subject_assignments').respond(200, assignmentCreatedData);
+ var promise = service.createAssignment(type, policy, perimeter, data);
+
+ $httpBackend.flush();
+
+ promise.then(function (result) {
+ expect(result.length).toBe(1);
+ var assignment = result[0];
+ expect(assignment.id).toBe('subjectAssignmentId1');
+ expect(assignment.policy_id).toBe('policyId1');
+ expect(assignment.subject_id).toBe('subjectId1');
+ expect(assignment.category_id).toBe('subjectCategoryId1');
+ expect(assignment.assignments.length).toBe(1);
+ expect(assignment.assignments[0]).toBe('subjectDataId1');
+ })
+ });
+
+ it('should remove assignment', function () {
+ var type = 'subject';
+ var policy = { id: 'policyId1' };
+ var perimeter = { id: 'subjectId1' };
+ var data = { id: 'subjectDataId1', category_id: 'subjectCategoryId1'};
+
+ $httpBackend.expectDELETE(URI.API + '/policies/policyId1/subject_assignments/subjectId1/subjectCategoryId1/subjectDataId1').respond(200);
+ service.removeAssignment(type, policy, perimeter, data);
+ $httpBackend.flush();
+ });
+
});
diff --git a/moon_dashboard/moon/static/moon/scss/moon.scss b/moon_dashboard/moon/static/moon/scss/moon.scss
index 20bf6c41..3cdbb6e3 100644
--- a/moon_dashboard/moon/static/moon/scss/moon.scss
+++ b/moon_dashboard/moon/static/moon/scss/moon.scss
@@ -51,4 +51,8 @@ details {
.input-file {
display: none !important;
+}
+
+.overflow-hidden {
+ overflow: hidden;
} \ No newline at end of file
diff --git a/moon_dashboard/run.sh b/moon_dashboard/run.sh
index bf18faa2..9a68ca6e 100644
--- a/moon_dashboard/run.sh
+++ b/moon_dashboard/run.sh
@@ -1,26 +1,42 @@
#!/bin/sh
# sudo docker run -ti --rm -p 8000:8000 -e MANAGER_HOST=localhost -e MANAGER_PORT=30001 -e KEYSTONE_HOST=localhost -e KEYSTONE_PORT=30005 moonplatform/dashboard:dev
+echo -----------------------------------
+export OPENSTACK_KEYSTONE_URL="http://${KEYSTONE_HOST}:${KEYSTONE_PORT}/identity/v3"
+echo MANAGER_HOST=${MANAGER_HOST}
+echo MANAGER_PORT=${MANAGER_PORT}
+echo KEYSTONE_HOST=${KEYSTONE_HOST}
+echo KEYSTONE_PORT=${KEYSTONE_PORT}
+echo OPENSTACK_HOST=${OPENSTACK_HOST}
+echo OPENSTACK_KEYSTONE_URL=${OPENSTACK_KEYSTONE_URL}
+echo SERVER_IP_ADDR=${SERVER_IP_ADDR}
+echo -----------------------------------
+
CONSTANT_FILE=/root/horizon/openstack_dashboard/dashboards/moon/static/moon/js/moon.module.js
-sed "s/{{MANAGER_HOST}}/$MANAGER_HOST/g" -i $CONSTANT_FILE
-sed "s/{{MANAGER_PORT}}/$MANAGER_PORT/g" -i $CONSTANT_FILE
-sed "s/{{KEYSTONE_HOST}}/$KEYSTONE_HOST/g" -i $CONSTANT_FILE
-sed "s/{{KEYSTONE_PORT}}/$KEYSTONE_PORT/g" -i $CONSTANT_FILE
+sed "s/{{MANAGER_HOST}}/${MANAGER_HOST}/g" -i ${CONSTANT_FILE}
+sed "s/{{MANAGER_PORT}}/${MANAGER_PORT}/g" -i ${CONSTANT_FILE}
+sed "s/{{KEYSTONE_HOST}}/${KEYSTONE_HOST}/g" -i ${CONSTANT_FILE}
+sed "s/{{KEYSTONE_PORT}}/${KEYSTONE_PORT}/g" -i ${CONSTANT_FILE}
cd /root/horizon
LOCAL_SETTINGS=/root/horizon/openstack_dashboard/local/local_settings.py
-sed "s/OPENSTACK_HOST = \"127.0.0.1\"/OPENSTACK_HOST = \"${OPENSTACK_HOST}\"/" -i $LOCAL_SETTINGS
-sed "s#OPENSTACK_KEYSTONE_URL = \"http:\/\/%s:5000\/v2.0\" % OPENSTACK_HOST#OPENSTACK_KEYSTONE_URL = \"${OPENSTACK_KEYSTONE_URL}\"#" -i $LOCAL_SETTINGS
+
+sed "s/OPENSTACK_HOST = \"127.0.0.1\"/OPENSTACK_HOST = \"${OPENSTACK_HOST}\"/" -i ${LOCAL_SETTINGS}
+sed "s#OPENSTACK_KEYSTONE_URL = \"http://%s:5000/v3\" % OPENSTACK_HOST#OPENSTACK_KEYSTONE_URL = \"${OPENSTACK_KEYSTONE_URL}\"#" -i ${LOCAL_SETTINGS}
+sed "s/#ALLOWED_HOSTS = \['horizon.example.com', \]/ALLOWED_HOSTS = \['${SERVER_IP_ADDR}'\]/" -i ${LOCAL_SETTINGS}
echo -----------------
-grep OPENSTACK_HOST $LOCAL_SETTINGS
-grep OPENSTACK_KEYSTONE_URL LOCAL_SETTINGS
+grep OPENSTACK_HOST ${LOCAL_SETTINGS}
+grep ALLOWED_HOSTS ${LOCAL_SETTINGS}
echo -----------------
+export NO_PROXY=127.0.0.1,10.0.2.15,10.96.0.0/12,192.168.0.0/16,10.192.118.95,10.192.118.96,keystone,manager,devstack
+
+echo "${KEYSTONE_HOST} devstack, keystone" | tee -a /etc/hosts
-echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $CONSTANT_FILE"
-cat $CONSTANT_FILE
+echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ${CONSTANT_FILE}"
+cat ${CONSTANT_FILE}
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
-tox -e runserver -- 0.0.0.0:8000 \ No newline at end of file
+tox -e runserver -- 0.0.0.0:8000
diff --git a/moon_dashboard/setup.cfg b/moon_dashboard/setup.cfg
index f68765dd..9cf3f779 100644
--- a/moon_dashboard/setup.cfg
+++ b/moon_dashboard/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = moon
-version=1.2.0
+version=1.5.0
summary = A dashboard plugin for Moon
description-file =
README.rst